知识大全 Spring事务管理高级应用难点剖析(4)
Posted 知
篇首语:夫学须志也,才须学也。非学无以广才,非志无以成学。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Spring事务管理高级应用难点剖析(4)相关的知识,希望对你有一定的参考价值。
Spring事务管理高级应用难点剖析(4) 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
多线程的困惑
由于Spring事务管理器是通过线程相关的ThreadLocal来保存数据访问基础设施 再结合IOC和AOP实现高级声明式事务的功能 所以Spring的事务天然地和线程有着千丝万缕的联系
我们知道Web容器本身就是多线程的 Web容器为一个Http请求创建一个独立的线程 所以由此请求所牵涉到的Spring容器中的Bean也是运行于多线程的环境下 在绝大多数情况下 Spring的Bean都是单实例的(singleton) 单实例Bean的最大的好处是线程无关性 不存在多线程并发访问的问题 也即是线程安全的 一个类能够以单实例的方式运行的前提是 无状态 即一个类不能拥有状态化的成员变量 我们知道 在传统的编程中 DAO必须执有一个Connection 而Connection即是状态化的对象 所以传统的DAO不能做成单实例的 每次要用时都必须new一个新的实例 传统的Service由于将有状态的DAO作为成员变量 所以传统的Service本身也是有状态的
但是在Spring中 DAO和Service都以单实例的方式存在 Spring是通过ThreadLocal将有状态的变量(如Connection等)本地线程化 达到另一个层面上的 线程无关 从而实现线程安全 Spring不遗余力地将状态化的对象无状态化 就是要达到单实例化Bean的目的 由于Spring已经通过ThreadLocal的设施将Bean无状态化 所以Spring中单实例Bean对线程安全问题拥有了一种天生的免疫能力 不但单实例的Service可以成功运行于多线程环境中 Service本身还可以自由地启动独立线程以执行其它的Service 下面 通过一个实例对此进行描述
清单 UserService java在事务方法中启动独立线程运行另一个事务方法
@Service( userService )
publicclassUserServiceextendsBaseService
@Autowired
privateJdbcTemplatejdbcTemplate;
@Autowired
privateScoreServicescoreService;
//①在logon方法体中启动一个独立的线程 在该独立的线程中执行ScoreService#addScore()方法
publicvoidlogon(StringuserName)
System out println( logonmethod );
updateLastLogonTime(userName);
ThreadmyThread=newMyThread(this scoreService userName );
myThread start();
publicvoidupdateLastLogonTime(StringuserName)
System out println( updateLastLogonTime );
Stringsql= UPDATEt_useruSETu last_logon_time=?WHEREuser_name=? ;
jdbcTemplate update(sql System currentTimeMillis() userName);
//②封装ScoreService#addScore()的线程
privateclassMyThreadextendsThread
privateScoreServicescoreService;
privateStringuserName;
privateinttoAdd;
privateMyThread(ScoreServicescoreService StringuserName inttoAdd)
this scoreService=scoreService;
this userName=userName;
this toAdd=toAdd;
publicvoidrun()
scoreService addScore(userName toAdd);
将日志级别设置为DEBUG 执行UserService#logon()方法 观察以下输出的日志
清单 执行日志
[main](AbstractPlatformTransactionManager java: ) Creatingnewtransactionwithname
[user multithread UserService logon]:PROPAGATION_REQUIRED ISOLATION_DEFAULT①
[main](DataSourceTransactionManager java: ) AcquiredConnection
[mons dbcp PoolableConnection@ ]forJDBCtransaction
logonmethod
updateLastLogonTime
[main](JdbcTemplate java: ) ExecutingpreparedSQLupdate
[main](JdbcTemplate java: ) ExecutingpreparedSQLstatement
[UPDATEt_useruSETu last_logon_time=?WHEREuser_name=?]
[main](JdbcTemplate java: ) SQLupdateaffected rows
[main](AbstractPlatformTransactionManager java: ) Initiatingtransactionmit
[Thread ](AbstractPlatformTransactionManager java: )
Creatingnewtransactionwithname[user multithread ScoreService addScore]:
PROPAGATION_REQUIRED ISOLATION_DEFAULT②
[main](DataSourceTransactionManager java: ) CommittingJDBCtransaction
onConnection[mons dbcp PoolableConnection@ ]③
[main](DataSourceTransactionManager java: ) ReleasingJDBCConnection
[mons dbcp PoolableConnection@ ]aftertransaction
[main](DataSourceUtils java: ) ReturningJDBCConnectiontoDataSource
[Thread ](DataSourceTransactionManager java: ) AcquiredConnection
[mons dbcp PoolableConnection@ dc ]forJDBCtransaction
addScore
[main](JdbcTemplate java: ) ExecutingSQLstatement
[DELETEFROMt_userWHEREuser_name= tom ]
[main](DataSourceUtils java: ) FetchingJDBCConnectionfromDataSource
[Thread ](JdbcTemplate java: ) ExecutingpreparedSQLupdate
[Thread ](JdbcTemplate java: ) ExecutingpreparedSQLstatement
[UPDATEt_useruSETu score=u score+?WHEREuser_name=?]
[main](DataSourceUtils java: ) ReturningJDBCConnectiontoDataSource
[Thread ](JdbcTemplate java: ) SQLupdateaffected rows
[Thread ](AbstractPlatformTransactionManager java: ) Initiatingtransactionmit
[Thread ](DataSourceTransactionManager java: ) CommittingJDBCtransaction
onConnection[mons dbcp PoolableConnection@ dc ]④
[Thread ](DataSourceTransactionManager java: ) ReleasingJDBCConnection
[mons dbcp PoolableConnection@ dc ]aftertransaction
在①处 在主线程(main)执行的UserService#logon()方法的事务启动 在③处 其对应的事务提交 而在子线程(Thread )执行的ScoreService#addScore()方法的事务在②处启动 在④处对应的事务提交
所以 我们可以得出这样的结论 在相同线程中进行相互嵌套调用的事务方法工作于相同的事务中 如果这些相互嵌套调用的方法工作在不同的线程中 不同线程下的事务方法工作在独立的事务中
小结
Spring声明式事务是Spring最核心 最常用的功能 由于Spring通过IOC和AOP的功能非常透明地实现了声明式事务的功能 一般的开发者基本上无须了解Spring声明式事务的内部细节 仅需要懂得如何配置就可以了
但是在实际应用开发过程中 Spring的这种透明的高阶封装在带来便利的同时 也给我们带来了迷惑 就像通过流言传播的消息 最终听众已经不清楚事情的真相了 而这对于应用开发来说是很危险的 本系列文章通过剖析实际应用中给开发者造成迷惑的各种难点 通过分析Spring事务管理的内部运作机制将真相还原出来 在本文中 我们通过剖析了解到以下的真相
◆在没有事务管理的情况下 DAO照样可以顺利进行数据操作
◆将应用分成Web Service及DAO层只是一种参考的开发模式 并非是事务管理工作的前提条件
◆Spring通过事务传播机制可以很好地应对事务方法嵌套调用的情况 开发者无须为了事务管理而刻意改变服务方法的设计
◆由于单实例的对象不存在线程安全问题 所以进行事务管理增强的Bean可以很好地工作在多线程环境下
◆混合使用多种数据访问技术(如SpringJDBC+Hibernate)的事务管理问题
cha138/Article/program/Java/ky/201311/27939相关参考
VS2005数据存取层深入剖析高级篇 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!一扩展表格适配器
SpringMVC框架的高级配置(下) 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 上文介绍S
数据库连接池概述 数据库连接是一种关键的有限的昂贵的资源这一点在多用户的网页应用程序中体现得尤为突出对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性影响到程序的性能指标数据库连接池正是
高性能MySQL:对应用程序进行性能剖析 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 对应用程
引言 数据库的设计范式是数据库设计所需要满足的规范满足这些规范的数据库是简洁的结构明晰的同时不会发生插入(insert)删除(delete)和更新(update)操作异常反之则是乱七八糟不仅给数
自动内存管理机制深入剖析-C#分析篇 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 在NETFr
中水回用技术的目的是通过必要的水处理方法去除水中的杂质,使之符合中水回用水质标准。处理的方法应根据中水的水源和用水对象对水质的要求确定。在中水回用处理过程中,有的方法除了具有某一特定的处理效果外,往往
中水回用技术的目的是通过必要的水处理方法去除水中的杂质,使之符合中水回用水质标准。处理的方法应根据中水的水源和用水对象对水质的要求确定。在中水回用处理过程中,有的方法除了具有某一特定的处理效果外,往往
中水回用技术的目的是通过必要的水处理方法去除水中的杂质,使之符合中水回用水质标准。处理的方法应根据中水的水源和用水对象对水质的要求确定。在中水回用处理过程中,有的方法除了具有某一特定的处理效果外,往往
全面剖析Delphi2006新增特性4 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 这些功能或