最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java的Hibernate框架數(shù)據(jù)庫操作中鎖的使用和查詢類型

 更新時間:2016年01月22日 08:55:39   作者:cdai  
這篇文章主要介紹了Java的Hibernate框架數(shù)據(jù)庫操作中鎖的使用和查詢類型,Hibernate是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下

 Hibernate與數(shù)據(jù)庫鎖
一、為什么要使用鎖?

要想弄清楚鎖機制存在的原因,首先要了解事務的概念。
事務是對數(shù)據(jù)庫一系列相關的操作,它必須具備ACID特征:

  • A(原子性):要么全部成功,要么全部撤銷。
  • C(一致性):要保持數(shù)據(jù)庫的一致性。
  • I(隔離性):不同事務操作相同數(shù)據(jù)時,要有各自的數(shù)據(jù)空間。
  • D(持久性):一旦事務成功結束,它對數(shù)據(jù)庫所做的更新必須永久保持。

我們常用的關系型數(shù)據(jù)庫RDBMS實現(xiàn)了事務的這些特性。其中,原子性、
一致性和持久性都是采用日志來保證的。而隔離性就是由今天我們關注的
鎖機制來實現(xiàn)的,這就是為什么我們需要鎖機制。

如果沒有鎖,對隔離性不加控制,可能會造成哪些后果呢?

  1. 更新丟失:事務1提交的數(shù)據(jù)被事務2覆蓋。
  2. 臟讀:事務2查詢到了事務1未提交的數(shù)據(jù)。
  3. 虛讀:事務2查詢到了事務1提交的新建數(shù)據(jù)。
  4. 不可重復讀:事務2查詢到了事務1提交的更新數(shù)據(jù)。

下面來看Hibernate的例子,兩個線程分別開啟兩個事務操作tb_account表中
的同一行數(shù)據(jù)col_id=1。

package com.cdai.orm.hibernate.annotation; 
 
import java.io.Serializable; 
 
import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.Table; 
 
@Entity 
@Table(name = "tb_account") 
public class Account implements Serializable { 
 
  private static final long serialVersionUID = 5018821760412231859L; 
 
  @Id 
  @Column(name = "col_id") 
  private long id; 
   
  @Column(name = "col_balance") 
  private long balance; 
 
  public Account() { 
  } 
   
  public Account(long id, long balance) { 
    this.id = id; 
    this.balance = balance; 
  } 
 
  public long getId() { 
    return id; 
  } 
 
  public void setId(long id) { 
    this.id = id; 
  } 
 
  public long getBalance() { 
    return balance; 
  } 
 
  public void setBalance(long balance) { 
    this.balance = balance; 
  } 
 
  @Override 
  public String toString() { 
    return "Account [id=" + id + ", balance=" + balance + "]"; 
  } 
   
} 

package com.cdai.orm.hibernate.transaction; 
 
import org.hibernate.Session; 
import org.hibernate.SessionFactory; 
import org.hibernate.Transaction; 
import org.hibernate.cfg.AnnotationConfiguration; 
 
import com.cdai.orm.hibernate.annotation.Account; 
 
public class DirtyRead { 
 
  public static void main(String[] args) { 
 
    final SessionFactory sessionFactory = new AnnotationConfiguration(). 
        addFile("hibernate/hibernate.cfg.xml").        
        configure(). 
        addPackage("com.cdai.orm.hibernate.annotation"). 
        addAnnotatedClass(Account.class). 
        buildSessionFactory(); 
     
    Thread t1 = new Thread() { 
       
      @Override 
      public void run() { 
        Session session1 = sessionFactory.openSession(); 
        Transaction tx1 = null; 
        try { 
          tx1 = session1.beginTransaction(); 
          System.out.println("T1 - Begin trasaction"); 
          Thread.sleep(500); 
           
          Account account = (Account)  
              session1.get(Account.class, new Long(1)); 
          System.out.println("T1 - balance=" + account.getBalance()); 
          Thread.sleep(500); 
           
          account.setBalance(account.getBalance() + 100); 
          System.out.println("T1 - Change balance:" + account.getBalance()); 
           
          tx1.commit(); 
          System.out.println("T1 - Commit transaction"); 
          Thread.sleep(500); 
        } 
        catch (Exception e) { 
          e.printStackTrace(); 
          if (tx1 != null) 
            tx1.rollback(); 
        }  
        finally { 
          session1.close(); 
        } 
      } 
       
    }; 
     
    // 3.Run transaction 2 
    Thread t2 = new Thread() { 
       
      @Override 
      public void run() { 
        Session session2 = sessionFactory.openSession(); 
        Transaction tx2 = null; 
        try { 
          tx2 = session2.beginTransaction(); 
          System.out.println("T2 - Begin trasaction"); 
          Thread.sleep(500); 
           
          Account account = (Account)  
              session2.get(Account.class, new Long(1)); 
          System.out.println("T2 - balance=" + account.getBalance()); 
          Thread.sleep(500); 
           
          account.setBalance(account.getBalance() - 100); 
          System.out.println("T2 - Change balance:" + account.getBalance()); 
           
          tx2.commit(); 
          System.out.println("T2 - Commit transaction"); 
          Thread.sleep(500); 
        } 
        catch (Exception e) { 
          e.printStackTrace(); 
          if (tx2 != null) 
            tx2.rollback(); 
        }  
        finally { 
          session2.close(); 
        } 
      } 
       
    }; 
     
    t1.start(); 
    t2.start(); 
     
    while (t1.isAlive() || t2.isAlive()) { 
      try { 
        Thread.sleep(2000L); 
      } catch (InterruptedException e) { 
      } 
    } 
     
    System.out.println("Both T1 and T2 are dead."); 
    sessionFactory.close(); 
     
  } 
 
} 

事務1將col_balance減小100,而事務2將其減少100,最終結果可能是0,也
可能是200,事務1或2的更新可能會丟失。log輸出也印證了這一點,事務1和2
的log交叉打印。

T1 - Begin trasaction
T2 - Begin trasaction
Hibernate: select account0_.col_id as col1_0_0_, account0_.col_balance as col2_0_0_ from tb_account account0_ where account0_.col_id=?
Hibernate: select account0_.col_id as col1_0_0_, account0_.col_balance as col2_0_0_ from tb_account account0_ where account0_.col_id=?
T1 - balance=100
T2 - balance=100
T2 - Change balance:0
T1 - Change balance:200
Hibernate: update tb_account set col_balance=? where col_id=?
Hibernate: update tb_account set col_balance=? where col_id=?
T1 - Commit transaction
T2 - Commit transaction
Both T1 and T2 are dead.

由此可見,隔離性是一個需要慎重考慮的問題,理解鎖很有必要。


二、有多少種鎖?

常見的有共享鎖、更新鎖和獨占鎖。

1.共享鎖:用于讀數(shù)據(jù)操作,允許其他事務同時讀取。當事務執(zhí)行select語句時,
數(shù)據(jù)庫自動為事務分配一把共享鎖來鎖定讀取的數(shù)據(jù)。
2.獨占鎖:用于修改數(shù)據(jù),其他事務不能讀取也不能修改。當事務執(zhí)行insert、
update和delete時,數(shù)據(jù)庫會自動分配。
3.更新鎖:用于避免更新操作時共享鎖造成的死鎖,比如事務1和2同時持有
共享鎖并等待獲得獨占鎖。當執(zhí)行update時,事務先獲得更新鎖,然后將
更新鎖升級成獨占鎖,這樣就避免了死鎖。

此外,這些鎖都可以施加到數(shù)據(jù)庫中不同的對象上,即這些鎖可以有不同的粒度。
如數(shù)據(jù)庫級鎖、表級鎖、頁面級鎖、鍵級鎖和行級鎖。

所以鎖是有很多種的,這么多鎖要想完全掌握靈活使用太難了,我們又不是DBA。
怎么辦?還好,鎖機制對于我們一般用戶來說是透明的,數(shù)據(jù)庫會自動添加合適的
鎖,并在適當?shù)臅r機自動升級、降級各種鎖,真是太周到了!我們只需要做的就是
學會根據(jù)不同的業(yè)務需求,設置好隔離級別就可以了。


三、怎樣設置隔離級別?

一般來說,數(shù)據(jù)庫系統(tǒng)會提供四種事務隔離級別供用戶選擇:

1.Serializable(串行化):當兩個事務同時操縱相同數(shù)據(jù)時,事務2只能停下來等。

2.Repeatable Read(可重復讀):事務1能看到事務2新插入的數(shù)據(jù),不能看到對
已有數(shù)據(jù)的更新。

3.Read Commited(讀已提交數(shù)據(jù)):事務1能看到事務2新插入和更新的數(shù)據(jù)。

4.Read Uncommited(讀未提交數(shù)據(jù)):事務1能看到事務2沒有提交的插入和更新
數(shù)據(jù)。


四、應用程序中的鎖

當數(shù)據(jù)庫采用Read Commited隔離級別時,可以在應用程序中采用悲觀鎖或樂觀鎖。

1.悲觀鎖:假定當前事務操作的數(shù)據(jù)肯定還會有其他事務訪問,因此悲觀地在應用
程序中顯式指定采用獨占鎖來鎖定數(shù)據(jù)資源。在MySQL、Oracle中支持以下形式:

   select ... for update

顯式地讓select采用獨占鎖鎖定查詢的記錄,其他事務要查詢、更新或刪除這些被
鎖定的數(shù)據(jù),都要等到該事務結束后才行。

在Hibernate中,可以在load時傳入LockMode.UPGRADE來采用悲觀鎖。修改前面的例子,
在事務1和2的get方法調(diào)用處,多傳入一個LockMode參數(shù)。從log中可以看出,事務1和2
不再是交叉運行,事務2等待事務1結束后才可以讀取數(shù)據(jù),所以最終col_balance值是正確
的100。

package com.cdai.orm.hibernate.transaction; 
 
import org.hibernate.LockMode; 
import org.hibernate.Session; 
import org.hibernate.SessionFactory; 
import org.hibernate.Transaction; 
 
import com.cdai.orm.hibernate.annotation.Account; 
import com.cdai.orm.hibernate.annotation.AnnotationHibernate; 
 
public class UpgradeLock { 
 
  @SuppressWarnings("deprecation") 
  public static void main(String[] args) { 
 
    final SessionFactory sessionFactory = AnnotationHibernate.createSessionFactory();  
 
    // Run transaction 1 
    Thread t1 = new Thread() { 
       
      @Override 
      public void run() { 
        Session session1 = sessionFactory.openSession(); 
        Transaction tx1 = null; 
        try { 
          tx1 = session1.beginTransaction(); 
          System.out.println("T1 - Begin trasaction"); 
          Thread.sleep(500); 
           
          Account account = (Account)  
              session1.get(Account.class, new Long(1), LockMode.UPGRADE); 
          System.out.println("T1 - balance=" + account.getBalance()); 
          Thread.sleep(500); 
           
          account.setBalance(account.getBalance() + 100); 
          System.out.println("T1 - Change balance:" + account.getBalance()); 
           
          tx1.commit(); 
          System.out.println("T1 - Commit transaction"); 
          Thread.sleep(500); 
        } 
        catch (Exception e) { 
          e.printStackTrace(); 
          if (tx1 != null) 
            tx1.rollback(); 
        }  
        finally { 
          session1.close(); 
        } 
      } 
       
    }; 
     
    // Run transaction 2 
    Thread t2 = new Thread() { 
       
      @Override 
      public void run() { 
        Session session2 = sessionFactory.openSession(); 
        Transaction tx2 = null; 
        try { 
          tx2 = session2.beginTransaction(); 
          System.out.println("T2 - Begin trasaction"); 
          Thread.sleep(500); 
           
          Account account = (Account)  
              session2.get(Account.class, new Long(1), LockMode.UPGRADE); 
          System.out.println("T2 - balance=" + account.getBalance()); 
          Thread.sleep(500); 
           
          account.setBalance(account.getBalance() - 100); 
          System.out.println("T2 - Change balance:" + account.getBalance()); 
           
          tx2.commit(); 
          System.out.println("T2 - Commit transaction"); 
          Thread.sleep(500); 
        } 
        catch (Exception e) { 
          e.printStackTrace(); 
          if (tx2 != null) 
            tx2.rollback(); 
        }  
        finally { 
          session2.close(); 
        } 
      } 
       
    }; 
     
    t1.start(); 
    t2.start(); 
     
    while (t1.isAlive() || t2.isAlive()) { 
      try { 
        Thread.sleep(2000L); 
      } catch (InterruptedException e) { 
      } 
    } 
     
    System.out.println("Both T1 and T2 are dead."); 
    sessionFactory.close(); 
 
  } 
 
} 
T1 - Begin trasaction
T2 - Begin trasaction
Hibernate: select account0_.col_id as col1_0_0_, account0_.col_balance as col2_0_0_ from tb_account account0_ with (updlock, rowlock) where account0_.col_id=?
Hibernate: select account0_.col_id as col1_0_0_, account0_.col_balance as col2_0_0_ from tb_account account0_ with (updlock, rowlock) where account0_.col_id=?
T2 - balance=100
T2 - Change balance:0
Hibernate: update tb_account set col_balance=? where col_id=?
T2 - Commit transaction
T1 - balance=0
T1 - Change balance:100
Hibernate: update tb_account set col_balance=? where col_id=?
T1 - Commit transaction
Both T1 and T2 are dead.

Hibernate對于SQLServer 2005會執(zhí)行SQL:

復制代碼 代碼如下:

select account0_.col_id as col1_0_0_, account0_.col_balance as col2_0_0_ from tb_account account0_ with (updlock, rowlock) where account0_.col_id=?


為選定的col_id為1的數(shù)據(jù)行加上行鎖和更新鎖。

2.樂觀鎖:假定當前事務操作的數(shù)據(jù)不會有其他事務同時訪問,因此完全依靠數(shù)據(jù)庫
的隔離級別來自動管理鎖的工作。在應用程序中采用版本控制來避免可能低概率出現(xiàn)
的并發(fā)問題。

在Hibernate中,使用Version注解來定義版本號字段。

201612285333338.png (351×120)

將DirtyLock中的Account對象替換成AccountVersion,其他代碼不變,執(zhí)行出現(xiàn)異常。

package com.cdai.orm.hibernate.transaction; 
 
import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.Table; 
import javax.persistence.Version; 
 
@Entity 
@Table(name = "tb_account_version") 
public class AccountVersion { 
 
  @Id 
  @Column(name = "col_id") 
  private long id; 
   
  @Column(name = "col_balance") 
  private long balance; 
   
  @Version 
  @Column(name = "col_version") 
  private int version; 
 
  public AccountVersion() { 
  } 
 
  public AccountVersion(long id, long balance) { 
    this.id = id; 
    this.balance = balance; 
  } 
 
  public long getId() { 
    return id; 
  } 
 
  public void setId(long id) { 
    this.id = id; 
  } 
 
  public long getBalance() { 
    return balance; 
  } 
 
  public void setBalance(long balance) { 
    this.balance = balance; 
  } 
 
  public int getVersion() { 
    return version; 
  } 
 
  public void setVersion(int version) { 
    this.version = version; 
  } 
   
} 

log如下:

T1 - Begin trasaction
T2 - Begin trasaction
Hibernate: select accountver0_.col_id as col1_0_0_, accountver0_.col_balance as col2_0_0_, accountver0_.col_version as col3_0_0_ from tb_account_version accountver0_ where accountver0_.col_id=?
Hibernate: select accountver0_.col_id as col1_0_0_, accountver0_.col_balance as col2_0_0_, accountver0_.col_version as col3_0_0_ from tb_account_version accountver0_ where accountver0_.col_id=?
T1 - balance=1000
T2 - balance=1000
T1 - Change balance:900
T2 - Change balance:1100
Hibernate: update tb_account_version set col_balance=?, col_version=? where col_id=? and col_version=?
Hibernate: update tb_account_version set col_balance=?, col_version=? where col_id=? and col_version=?
T1 - Commit transaction
2264 [Thread-2] ERROR org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.cdai.orm.hibernate.transaction.AccountVersion#1]
   at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1934)
   at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2578)
   at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2478)
   at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2805)
   at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:114)
   at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:260)
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:180)
   at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
   at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
   at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
   at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:375)
   at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
   at com.cdai.orm.hibernate.transaction.VersionLock$2.run(VersionLock.java:93)
Both T1 and T2 are dead.

由于樂觀鎖完全將事務隔離交給數(shù)據(jù)庫來控制,所以事務1和2交叉運行了,事務1提交
成功并將col_version改為1,然而事務2提交時已經(jīng)找不到col_version為0的數(shù)據(jù)了,所以
拋出了異常。

201612285414974.png (353×131)

Hibernate查詢方法比較
Hibernate主要有三種查詢方法:

1.HQL (Hibernate Query Language)

和SQL很類似,支持分頁、連接、分組、聚集函數(shù)和子查詢等特性,
但HQL是面向對象的,而不是面向關系數(shù)據(jù)庫中的表。正因查詢語句
是面向Domain對象的,所以使用HQL可以獲得跨平臺的好處,Hibernate
會自動幫我們根據(jù)不同的數(shù)據(jù)庫翻譯成不同的SQL語句。這在需要支持
多種數(shù)據(jù)庫或者數(shù)據(jù)庫遷移的應用中是十分方便的。

但得到方便的同時,由于SQL語句是由Hibernate自動生成的,所以這不
利于SQL語句的效率優(yōu)化和調(diào)試,當數(shù)據(jù)量很大時可能會有效率問題,
出了問題也不便于排查解決。

2.QBC/QBE (Query by Criteria/Example)

QBC/QBE是通過組裝查詢條件或者模板對象來執(zhí)行查詢的。這在需要
靈活地支持許多查詢條件自由組合的應用中是比較方便的。同樣的問題
是由于查詢語句是自由組裝的,創(chuàng)建一條語句的代碼可能很長,并且
包含許多分支條件,很不便于優(yōu)化和調(diào)試。

3.SQL

Hibernate也支持直接執(zhí)行SQL的查詢方式。這種方式犧牲了Hibernate跨
數(shù)據(jù)庫的優(yōu)點,手工地編寫底層SQL語句,從而獲得最好的執(zhí)行效率,
相對前兩種方法,優(yōu)化和調(diào)試方便了一些。

下面來看一組簡單的例子。

package com.cdai.orm.hibernate.query; 
 
import java.util.Arrays; 
import java.util.List; 
 
import org.hibernate.Criteria; 
import org.hibernate.Query; 
import org.hibernate.Session; 
import org.hibernate.SessionFactory; 
import org.hibernate.cfg.AnnotationConfiguration; 
import org.hibernate.criterion.Criterion; 
import org.hibernate.criterion.Example; 
import org.hibernate.criterion.Expression; 
 
import com.cdai.orm.hibernate.annotation.Account; 
 
public class BasicQuery { 
 
  public static void main(String[] args) { 
 
    SessionFactory sessionFactory = new AnnotationConfiguration(). 
                      addFile("hibernate/hibernate.cfg.xml").        
                      configure(). 
                      addPackage("com.cdai.orm.hibernate.annotation"). 
                      addAnnotatedClass(Account.class). 
                      buildSessionFactory(); 
 
    Session session = sessionFactory.openSession(); 
 
    // 1.HQL 
    Query query = session.createQuery("from Account as a where a.id=:id"); 
    query.setLong("id", 1); 
    List result = query.list(); 
    for (Object row : result) { 
      System.out.println(row); 
    } 
 
    // 2.QBC 
    Criteria criteria = session.createCriteria(Account.class); 
    criteria.add(Expression.eq("id", new Long(2))); 
    result = criteria.list(); 
    for (Object row : result) { 
      System.out.println(row); 
    } 
     
    // 3.QBE 
    Account example= new Account(); 
    example.setBalance(100); 
    result = session.createCriteria(Account.class). 
            add(Example.create(example)). 
            list(); 
    for (Object row : result) { 
      System.out.println(row); 
    } 
     
    // 4.SQL 
    query = session.createSQLQuery( 
        " select top 10 * from tb_account order by col_id desc "); 
    result = query.list(); 
    for (Object row : result) { 
      System.out.println(Arrays.toString((Object[]) row)); 
  } 
     
    session.close(); 
  } 
 
} 
Hibernate: select account0_.col_id as col1_0_, account0_.col_balance as col2_0_ from tb_account account0_ where account0_.col_id=?
Account [id=1, balance=100]
Hibernate: select this_.col_id as col1_0_0_, this_.col_balance as col2_0_0_ from tb_account this_ where this_.col_id=?
Account [id=2, balance=100]
Hibernate: select this_.col_id as col1_0_0_, this_.col_balance as col2_0_0_ from tb_account this_ where (this_.col_balance=?)
Account [id=1, balance=100]
Account [id=2, balance=100]
Hibernate: select top 10 * from tb_account order by col_id desc
[2, 100]
[1, 100]

從log中可以清楚的看到Hibernate對于生成的SQL語句的控制,具體選擇
哪種查詢方式就要看具體應用了。

相關文章

  • Springboot整合knife4j與shiro的操作

    Springboot整合knife4j與shiro的操作

    這篇文章主要介紹了Springboot整合knife4j與shiro的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Springboot集成magic-api的詳細過程

    Springboot集成magic-api的詳細過程

    這篇文章主要介紹了Springboot集成magic-api的相關知識,本文結合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-06-06
  • Google Kaptcha 框架實現(xiàn)登錄驗證碼功能(SSM 和 SpringBoot)

    Google Kaptcha 框架實現(xiàn)登錄驗證碼功能(SSM 和 SpringBoot)

    這篇文章主要介紹了Google Kaptcha 實現(xiàn)登錄驗證碼(SSM 和 SpringBoot)功能,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-12-12
  • Java線程監(jiān)聽,意外退出線程后自動重啟的實現(xiàn)方法

    Java線程監(jiān)聽,意外退出線程后自動重啟的實現(xiàn)方法

    下面小編就為大家?guī)硪黄狫ava線程監(jiān)聽,意外退出線程后自動重啟的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • Java AtomicInteger類的重要方法和特性

    Java AtomicInteger類的重要方法和特性

    AtomicInteger是Java中的一個類,用于實現(xiàn)原子操作的整數(shù),AtomicInteger類主要用于處理整數(shù)類型的原子操作,本文給大家介紹Java AtomicInteger類的重要方法和特性,感興趣的朋友一起看看吧
    2023-10-10
  • Eolink上傳文件到Java后臺進行處理的示例代碼

    Eolink上傳文件到Java后臺進行處理的示例代碼

    這篇文章主要介紹了Eolink上傳文件到Java后臺進行處理,這里是上傳的excel表格數(shù)據(jù)并轉換為java集合對象、然后進行業(yè)務邏輯處理判斷最后保存到數(shù)據(jù)庫?,需要的朋友可以參考下
    2022-12-12
  • JVM的垃圾回收機制真是通俗易懂

    JVM的垃圾回收機制真是通俗易懂

    這篇文章主要為大家詳細介紹了JVM的垃圾回收機制,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Maven 不同環(huán)境靈活構建的步驟

    Maven 不同環(huán)境靈活構建的步驟

    在項目開發(fā)過程中,合理地使用Maven管理不同的構建環(huán)境(開發(fā)、測試、生產(chǎn))是提高項目管理效率和應對復雜項目需求的關鍵,本文就來介紹一下Maven 不同環(huán)境靈活構建的步驟,感興趣的可以了解一下
    2024-10-10
  • Java 重入鎖和讀寫鎖的具體使用

    Java 重入鎖和讀寫鎖的具體使用

    這篇文章主要介紹了Java 重入鎖和讀寫鎖的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • Java定義泛型方法實例分析

    Java定義泛型方法實例分析

    這篇文章主要介紹了Java定義泛型方法,結合實例形式分析了java定義泛型的相關操作技巧與注意事項,需要的朋友可以參考下
    2019-07-07

最新評論

赣榆县| 天门市| 南京市| 饶河县| 称多县| 侯马市| 泰兴市| 恩平市| 遵义县| 邻水| 贵阳市| 蓬安县| 广河县| 汾阳市| 台湾省| 邹平县| 文登市| 彭水| 崇仁县| 东阿县| 安远县| 曲靖市| 吉安市| 古蔺县| 铜山县| 达孜县| 青冈县| 汉沽区| 平舆县| 宜黄县| 佛坪县| 永定县| 兴安县| 玉山县| 丹棱县| 卢龙县| 卫辉市| 甘谷县| 寿光市| 迭部县| 广丰县|