日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring JDBC-混合框架的事务管理

發(fā)布時(shí)間:2025/3/21 javascript 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring JDBC-混合框架的事务管理 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  • 概述
  • 問題
  • 解決方案
  • 示例Hibernate Spring JDBC

概述

Spring 抽象的 DAO 體系兼容多種數(shù)據(jù)訪問技術(shù),它們各有特色,各有千秋。

  • Hibernate 是非常優(yōu)秀的 ORM 實(shí)現(xiàn)方案,但對(duì)底層 SQL 的控制不太方便

  • MyBatis 則通過模板化技術(shù)讓我們能方便地控制 SQL,但沒有 Hibernate 那樣高的開發(fā)效率

  • 自由度最高的當(dāng)然是直接使用 Spring JDBC 莫屬了,但是它也是最底層的,靈活的代價(jià)是代碼的繁復(fù)

很難說哪種數(shù)據(jù)訪問技術(shù)是最優(yōu)秀的,只有在某種特定的場(chǎng)景下,才能給出答案。所以在一個(gè)應(yīng)用中,往往采用多個(gè)數(shù)據(jù)訪問技術(shù):一般是兩種,一種采用 ORM 技術(shù)框架,而另一種采用偏 JDBC 的底層技術(shù)。


問題

當(dāng)我們采用:ORM 技術(shù)框架+ 偏 JDBC 的底層技術(shù)如何應(yīng)對(duì)事務(wù)管理的問題呢? 我們知道 Spring 為每種數(shù)據(jù)訪問技術(shù)提供了相應(yīng)的事務(wù)管理器,難道需要分別為它們配置對(duì)應(yīng)的事務(wù)管理器嗎?它們到底是如何協(xié)作,如何工作的呢?


解決方案

Spring 事務(wù)管理的為我們的提供了解決方案。

當(dāng)我們采用了一個(gè)高端 ORM 技術(shù)(Hibernate,JPA,JDO),同時(shí)采用一個(gè) JDBC 技術(shù)(Spring JDBC,MyBatis),由于前者的會(huì)話(Session)是對(duì)后者連接(Connection)的封裝,Spring 會(huì)“足夠智能地”在同一個(gè)事務(wù)線程讓前者的會(huì)話封裝后者的連接。所以,我們只要直接采用前者的事務(wù)管理器就可以了。


我們列舉下混合數(shù)據(jù)訪問技術(shù)所對(duì)應(yīng)的事務(wù)管理器:


示例:Hibernate + Spring JDBC

由于一般不會(huì)出現(xiàn)同時(shí)使用多個(gè) ORM 框架的情況(如 Hibernate + JPA),我們不擬對(duì)此命題展開論述,只重點(diǎn)研究 ORM 框架 + JDBC 框架的情況。

Hibernate + Spring JDBC 可能是被使用得最多的組合,我們通過實(shí)例來觀察事物的運(yùn)行情況。


User 使用了注解聲明的實(shí)體類

import javax.persistence.Entity; import javax.persistence.Table; import javax.persistence.Column; import javax.persistence.Id; import java.io.Serializable; @Entity @Table(name="T_USER") public class User implements Serializable{ @Id@Column(name = "USER_NAME") private String userName; private String password; private int score; @Column(name = "LAST_LOGON_TIME")private long lastLogonTime = 0; }

UserService 使用 Hibernate 數(shù)據(jù)訪問技術(shù)

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Service; import org.springframework.orm.hibernate3.HibernateTemplate; import org.apache.commons.dbcp.BasicDataSource; import user.User;@Service("userService") public class UserService extends BaseService {@Autowiredprivate HibernateTemplate hibernateTemplate;@Autowiredprivate ScoreService scoreService;public void logon(String userName) {System.out.println("logon method...");updateLastLogonTime(userName); //①使用Hibernate數(shù)據(jù)訪問技術(shù)scoreService.addScore(userName, 20); //②使用Spring JDBC數(shù)據(jù)訪問技術(shù)}public void updateLastLogonTime(String userName) {System.out.println("updateLastLogonTime...");User user = hibernateTemplate.get(User.class,userName);user.setLastLogonTime(System.currentTimeMillis());hibernateTemplate.flush(); //③請(qǐng)看下文的分析} }

在①處,使用 Hibernate 操作數(shù)據(jù),而在②處調(diào)用 ScoreService#addScore(),該方法內(nèi)部使用 Spring JDBC 操作數(shù)據(jù)。

在③處,我們顯式調(diào)用了 flush() 方法,將 Session 中的緩存同步到數(shù)據(jù)庫中,這個(gè)操作將即時(shí)向數(shù)據(jù)庫發(fā)送一條更新記錄的 SQL 語句

之所以要在此顯式執(zhí)行 flush() 方法,原因是:默認(rèn)情況下,Hibernate 要在事務(wù)提交時(shí)才將數(shù)據(jù)的更改同步到數(shù)據(jù)庫中,而事務(wù)提交發(fā)生在 logon() 方法返回前。

如果所有針對(duì)數(shù)據(jù)庫的更改都使用 Hibernate,這種數(shù)據(jù)同步延遲的機(jī)制不會(huì)產(chǎn)生任何問題。但是,我們?cè)?logon() 方法中同時(shí)采用了 Hibernate 和 Spring JDBC 混合數(shù)據(jù)訪問技術(shù)。

Spring JDBC 無法自動(dòng)感知 Hibernate 一級(jí)緩存,所以如果不及時(shí)調(diào)用 flush() 方法將數(shù)據(jù)更改同步到數(shù)據(jù)庫,則②處通過 Spring JDBC 進(jìn)行數(shù)據(jù)更改的結(jié)果將被 Hibernate 一級(jí)緩存中的更改覆蓋掉,因?yàn)?#xff0c;一級(jí)緩存在 logon() 方法返回前才同步到數(shù)據(jù)庫!


ScoreService :使用 Spring JDBC 數(shù)據(jù)訪問技術(shù)

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.apache.commons.dbcp.BasicDataSource;@Service("scoreUserService") public class ScoreService extends BaseService{@Autowiredprivate JdbcTemplate jdbcTemplate;public void addScore(String userName, int toAdd) {System.out.println("addScore...");String sql = "UPDATE t_user u SET u.score = u.score + ? WHERE user_name =?";jdbcTemplate.update(sql, toAdd, userName);//① 查看此處數(shù)據(jù)庫激活的連接數(shù)BasicDataSource basicDataSource = (BasicDataSource) jdbcTemplate.getDataSource();System.out.println("激活連接數(shù)量:"+basicDataSource.getNumActive());} }

關(guān)鍵配置文件

<!-- 使用Hibernate事務(wù)管理器 --> <bean id="hiberManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"p:sessionFactory-ref="sessionFactory"/><!-- 對(duì)所有繼承BaseService類的公用方法實(shí)施事務(wù)增強(qiáng) --> <aop:config proxy-target-class="true"><aop:pointcut id="serviceJdbcMethod"expression="within(com.artisan.BaseService+)"/><aop:advisor pointcut-ref="serviceJdbcMethod"advice-ref="hiberAdvice"/> </aop:config><tx:advice id="hiberAdvice" transaction-manager="hiberManager"><tx:attributes><tx:method name="*"/></tx:attributes> </tx:advice>

日志:

21:37:57,062 (AbstractPlatformTransactionManager.java:365) - Creating new transaction with name [com.artisan.UserService.logon]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT21:37:57,093 (SessionImpl.java:220) - opened session at timestamp: 1266640737021:37:57,093 (HibernateTransactionManager.java:493) - Opened new Session [org.hibernate.impl.SessionImpl@83020] for Hibernate transaction ①21:37:57,093 (HibernateTransactionManager.java:504) - Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl@83020]21:37:57,109 (JDBCTransaction.java:54) - begin…logon method... updateLastLogonTime... …21:37:57,109 (AbstractBatcher.java:401) - select user0_.USER_NAME as USER1_0_0_, user0_.LAST_LOGON_TIME as LAST2_0_0_, user0_.password as password0_0_, user0_.score as score0_0_ from T_USER user0_ where user0_.USER_NAME=?Hibernate: select user0_.USER_NAME as USER1_0_0_, user0_.LAST_LOGON_TIME as LAST2_0_0_, user0_.password as password0_0_, user0_.score as score0_0_ from T_USER user0_ where user0_.USER_NAME=?…21:37:57,187 (HibernateTemplate.java:422) - Not closing pre-bound Hibernate Session after HibernateTemplate21:37:57,187 (HibernateTemplate.java:397) - Found thread-bound Sessionfor HibernateTemplateHibernate: update T_USER set LAST_LOGON_TIME=?, password=?, score=? where USER_NAME=?…2017-09-26 21:37:57,203 DEBUG [main] (AbstractPlatformTransactionManager.java:470) - Participating in existing transaction ② addScore...2017-09-26 21:37:57,203 DEBUG [main] (JdbcTemplate.java:785) - Executing prepared SQL update2017-09-26 21:37:57,203 DEBUG [main] (JdbcTemplate.java:569)- Executing prepared SQL statement [UPDATE t_user u SET u.score = u.score + ? WHERE user_name =?]2017-09-26 21:37:57,203 DEBUG [main] (JdbcTemplate.java:794) - SQL update affected 1 rows激活連接數(shù)量:12017-09-26 21:37:57,203 DEBUG [main] (AbstractPlatformTransactionManager.java:752) - Initiating transaction commit 2017-09-26 21:37:57,203 DEBUG [main] (HibernateTransactionManager.java:652) - Committing Hibernate transaction on Session [org.hibernate.impl.SessionImpl@83020] ④2017-09-26 21:37:57,203 DEBUG [main] (JDBCTransaction.java:103) - commit ⑤

在①處 UserService#logon() 開啟一個(gè)新的事務(wù),
在②處 ScoreService#addScore() 方法加入到①處開啟的事務(wù)上下文中。
③處的輸出是 ScoreService#addScore() 方法內(nèi)部的輸出,匯報(bào)此時(shí)數(shù)據(jù)源激活的連接數(shù)為 1,這清楚地告訴我們 Hibernate 和 JDBC 這兩種數(shù)據(jù)訪問技術(shù)在同一事務(wù)上下文中“共用”一個(gè)連接。
在④處,提交 Hibernate 事務(wù),
接著在⑤處觸發(fā)調(diào)用底層的 Connection 提交事務(wù)。


使用 Hibernate 事務(wù)管理器后,可以混合使用 Hibernate 和 Spring JDBC 數(shù)據(jù)訪問技術(shù),它們將工作于同一事務(wù)上下文中。但是使用 Spring JDBC 訪問數(shù)據(jù)時(shí),Hibernate 的一級(jí)或二級(jí)緩存得不到同步,此外,一級(jí)緩存延遲數(shù)據(jù)同步機(jī)制可能會(huì)覆蓋 Spring JDBC 數(shù)據(jù)更改的結(jié)果。

由于混合數(shù)據(jù)訪問技術(shù)的方案的事務(wù)同步而緩存不同步的情況,所以最好用 Hibernate 完成讀寫操作,而用 Spring JDBC 完成讀的操作。比如用 Spring JDBC 進(jìn)行簡(jiǎn)要列表的查詢,而用 Hibernate 對(duì)查詢出的數(shù)據(jù)進(jìn)行維護(hù)。

如果確實(shí)要同時(shí)使用 Hibernate 和 Spring JDBC 讀寫數(shù)據(jù),則必須充分考慮到 Hibernate 緩存機(jī)制引發(fā)的問題:必須充分分析數(shù)據(jù)維護(hù)邏輯,根據(jù)需要,及時(shí)調(diào)用 Hibernate 的 flush() 方法,以免覆蓋 Spring JDBC 的更改,在 Spring JDBC 更改數(shù)據(jù)庫時(shí),維護(hù) Hibernate 的緩存。

可以將以上結(jié)論推廣到其它混合數(shù)據(jù)訪問技術(shù)的方案中,如 Hibernate+MyBatis,JPA+Spring JDBC,JDO+Spring JDBC 等

總結(jié)

以上是生活随笔為你收集整理的Spring JDBC-混合框架的事务管理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。