- 浏览: 1518266 次
- 性别:
- 来自: 厦门
博客专栏
-
Spring 3.x企业实...
浏览量:461831
文章分类
最新评论
-
JyeChou:
学习Spring必学的Java基础知识(1)----反射 -
hhzhaoheng:
...
《Spring4.x企业应用开发实战》光盘资料下载 -
renlongnian:
//assertReflectionEquals(user1, ...
单元测试系列之3:测试整合之王Unitils -
骑着蜗牛超F1:
huang_yong 写道我的经验是,只需定义三层:1.ent ...
Spring的事务管理难点剖析(2):应用分层的迷惑 -
wangyudong:
工具地址貌似更新了哦https://github.com/Wi ...
几种常用的REST webservice客户端测试工具
Spring通过单实例化Bean简化多线程问题
由于Spring的事务管理器是通过线程相关的ThreadLocal来保存数据访问基础设施(也即Connection实例),再结合IoC和AOP实现高级声明式事务的功能,所以Spring的事务天然地和线程有着千丝万缕的联系。
我们知道Web容器本身就是多线程的,Web容器为一个HTTP请求创建一个独立的线程(实际上大多数Web容器采用共享线程池),所以由此请求所牵涉到的Spring容器中的Bean也是运行于多线程的环境下。在绝大多数情况下,Spring的Bean都是单实例的(singleton),单实例Bean的最大好处是线程无关性,不存在多线程并发访问的问题,也就是线程安全的。
一个类能够以单实例的方式运行的前提是“无状态”:即一个类不能拥有状态化的成员变量。我们知道,在传统的编程中,DAO必须持有一个Connection,而Connection即是状态化的对象。所以传统的DAO不能做成单实例的,每次要用时都必须创建一个新的实例。传统的Service由于内部包含了若干个有状态的DAO成员变量,所以其本身也是有状态的。
但是在Spring中,DAO和Service都以单实例的方式存在。Spring是通过ThreadLocal将有状态的变量(如Connection等)本地线程化,达到另一个层面上的“线程无关”,从而实现线程安全。Spring不遗余力地将有状态的对象无状态化,就是要达到单实例化Bean的目的。
由于Spring已经通过ThreadLocal的设施将Bean无状态化,所以Spring中单实例Bean对线程安全问题拥有了一种天生的免疫能力。不但单实例的Service可以成功运行于多线程环境中,Service本身还可以自由地启动独立线程以执行其他的Service。
启动独立线程调用事务方法
将日志级别设置为DEBUG,执行UserService#logon()方法,观察以下输出日志:
在①处,在主线程(main)执行的UserService#logon()方法的事务启动,在②处,其对应的事务提交。而在子线程(Thread-2)执行的ScoreService#addScore()方法的事务在③处启动,在④处对应的事务提交。
所以,我们可以得出这样的结论:在相同线程中进行相互嵌套调用的事务方法工作于相同的事务中。如果这些相互嵌套调用的方法工作在不同的线程中,则不同线程下的事务方法工作在独立的事务中。
注:以上内容摘自《Spring 4.x企业应用开发实战》
嗯咯
请问问题在什么地方,请指出来。
正因为spring的bean是单实例的所以才可能有线程安全的问题,如果在实例中定义了属性就得注意线程的安全了,和servlet所遇到的线程安全是一样的意思。springmvc之所以不需要开发人员解决安全问题是因为controller采用了restful风格的方法级别的请求映射处理,而如果在service实例中定义了属性也是会出现线程安全的问题。具体去看看java的内存模型,里面说的就是jvm底层的线程原理。
请问问题在什么地方,请指出来。
意思就是说:
在单线程环境下,A方法调用B方法,两个方法都在同一个事务中。
在多线程环境下,A方法调用B方法,两个方法各自具有各自的事务(两个事务)。
一句话:多线程肯定多事务,单线程一般都是单事务,也可以配置成多事务。
请问作者理解是否正确?
PS:
也可以使用 ThreadPoolTaskExecutor 开启一个线程
由于Spring的事务管理器是通过线程相关的ThreadLocal来保存数据访问基础设施(也即Connection实例),再结合IoC和AOP实现高级声明式事务的功能,所以Spring的事务天然地和线程有着千丝万缕的联系。
我们知道Web容器本身就是多线程的,Web容器为一个HTTP请求创建一个独立的线程(实际上大多数Web容器采用共享线程池),所以由此请求所牵涉到的Spring容器中的Bean也是运行于多线程的环境下。在绝大多数情况下,Spring的Bean都是单实例的(singleton),单实例Bean的最大好处是线程无关性,不存在多线程并发访问的问题,也就是线程安全的。
一个类能够以单实例的方式运行的前提是“无状态”:即一个类不能拥有状态化的成员变量。我们知道,在传统的编程中,DAO必须持有一个Connection,而Connection即是状态化的对象。所以传统的DAO不能做成单实例的,每次要用时都必须创建一个新的实例。传统的Service由于内部包含了若干个有状态的DAO成员变量,所以其本身也是有状态的。
但是在Spring中,DAO和Service都以单实例的方式存在。Spring是通过ThreadLocal将有状态的变量(如Connection等)本地线程化,达到另一个层面上的“线程无关”,从而实现线程安全。Spring不遗余力地将有状态的对象无状态化,就是要达到单实例化Bean的目的。
由于Spring已经通过ThreadLocal的设施将Bean无状态化,所以Spring中单实例Bean对线程安全问题拥有了一种天生的免疫能力。不但单实例的Service可以成功运行于多线程环境中,Service本身还可以自由地启动独立线程以执行其他的Service。
启动独立线程调用事务方法
package com.baobaotao.multithread; 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.apache.commons.dbcp.BasicDataSource; @Service("userService") public class UserService extends BaseService { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private ScoreService scoreService; public void logon(String userName) { System.out.println("before userService.updateLastLogonTime method..."); updateLastLogonTime(userName); System.out.println("after userService.updateLastLogonTime method..."); //scoreService.addScore(userName, 20);//①在同一线程中调用scoreService#addScore() //②在一个新线程中执行scoreService#addScore() Thread myThread = new MyThread(this.scoreService, userName, 20);//使用一个新线程运行 myThread.start(); } public void updateLastLogonTime(String userName) { String sql = "UPDATE t_user u SET u.last_logon_time = ? WHERE user_name =?"; jdbcTemplate.update(sql, System.currentTimeMillis(), userName); } //③负责执行scoreService#addScore()的线程类 private class MyThread extends Thread { private ScoreService scoreService; private String userName; private int toAdd; private MyThread(ScoreService scoreService, String userName, int toAdd) { this.scoreService = scoreService; this.userName = userName; this.toAdd = toAdd; } public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("before scoreService.addScor method..."); scoreService.addScore(userName, toAdd); System.out.println("after scoreService.addScor method..."); } } }
将日志级别设置为DEBUG,执行UserService#logon()方法,观察以下输出日志:
引用
before userService.logon method...
//①创建一个事务
Creating new transaction with name [com.baobaotao.multithread.UserService.logon]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
Acquired Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] for JDBC transaction
…
SQL update affected 1 rows
after userService.updateLastLogonTime method...
Initiating transaction commit
//②提交①处开启的事务
Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver]
Releasing JDBC Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] after transaction
…
Returning JDBC Connection to DataSource
before scoreService.addScor method...
//③创建一个事务
Creating new transaction with name [com.baobaotao.multithread.ScoreService.addScore]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
Acquired Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] for JDBC transaction
…
SQL update affected 0 rows
Initiating transaction commit
//④提交③处开启的事务
Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver]
Releasing JDBC Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] after transaction
Returning JDBC Connection to DataSource
after scoreService.addScor method...
//①创建一个事务
Creating new transaction with name [com.baobaotao.multithread.UserService.logon]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
Acquired Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] for JDBC transaction
…
SQL update affected 1 rows
after userService.updateLastLogonTime method...
Initiating transaction commit
//②提交①处开启的事务
Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver]
Releasing JDBC Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] after transaction
…
Returning JDBC Connection to DataSource
before scoreService.addScor method...
//③创建一个事务
Creating new transaction with name [com.baobaotao.multithread.ScoreService.addScore]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
Acquired Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] for JDBC transaction
…
SQL update affected 0 rows
Initiating transaction commit
//④提交③处开启的事务
Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver]
Releasing JDBC Connection [jdbc:mysql://localhost:3306/sampledb, UserName=root@localhost, MySQL-AB JDBC Driver] after transaction
Returning JDBC Connection to DataSource
after scoreService.addScor method...
在①处,在主线程(main)执行的UserService#logon()方法的事务启动,在②处,其对应的事务提交。而在子线程(Thread-2)执行的ScoreService#addScore()方法的事务在③处启动,在④处对应的事务提交。
所以,我们可以得出这样的结论:在相同线程中进行相互嵌套调用的事务方法工作于相同的事务中。如果这些相互嵌套调用的方法工作在不同的线程中,则不同线程下的事务方法工作在独立的事务中。
注:以上内容摘自《Spring 4.x企业应用开发实战》
评论
8 楼
guojiew
2017-02-14
“Spring的Bean都是单实例的(singleton),单实例Bean的最大好处是线程无关性,不存在多线程并发访问的问题,也就是线程安全的。”
......真不懂你怎么得出的这个结论。。
......真不懂你怎么得出的这个结论。。
7 楼
gongrunlian
2016-05-16
gufachongyang02 写道
“Spring的Bean都是单实例的(singleton),单实例Bean的最大好处是线程无关性,不存在多线程并发访问的问题,也就是线程安全的。”
扯淡吧!!完全误导人
扯淡吧!!完全误导人
嗯咯
6 楼
gufachongyang02
2016-02-02
stamen 写道
gufachongyang02 写道
“Spring的Bean都是单实例的(singleton),单实例Bean的最大好处是线程无关性,不存在多线程并发访问的问题,也就是线程安全的。”
扯淡吧!!完全误导人
扯淡吧!!完全误导人
请问问题在什么地方,请指出来。
正因为spring的bean是单实例的所以才可能有线程安全的问题,如果在实例中定义了属性就得注意线程的安全了,和servlet所遇到的线程安全是一样的意思。springmvc之所以不需要开发人员解决安全问题是因为controller采用了restful风格的方法级别的请求映射处理,而如果在service实例中定义了属性也是会出现线程安全的问题。具体去看看java的内存模型,里面说的就是jvm底层的线程原理。
5 楼
stamen
2015-09-21
gufachongyang02 写道
“Spring的Bean都是单实例的(singleton),单实例Bean的最大好处是线程无关性,不存在多线程并发访问的问题,也就是线程安全的。”
扯淡吧!!完全误导人
扯淡吧!!完全误导人
请问问题在什么地方,请指出来。
4 楼
gufachongyang02
2015-09-09
“Spring的Bean都是单实例的(singleton),单实例Bean的最大好处是线程无关性,不存在多线程并发访问的问题,也就是线程安全的。”
扯淡吧!!完全误导人
扯淡吧!!完全误导人
3 楼
amoszhou
2012-11-23
有两个问题想问作者。
1.如果我的系统,有一办的DAO是用hibernate,另一半是用spring JDBC,如果我的事务只配置Hibernate事务,那么对JDBC是否也有效?
2.如果上述情况无效,需要配置多个事务管理器,也就是说spring jdbc事务和hibernate各配置一个, 那么在同一个方法中,如果既用了hibernate,又用了spring jdbc 那么配置两个事务管理器,会不会有影响(如果只配置一个Hibernate是可以正常工作嘛)
3. 在一个事务方法中,如果开始另外一个线程去调用另外一个事务方法,是否构成嵌套事务??
1.如果我的系统,有一办的DAO是用hibernate,另一半是用spring JDBC,如果我的事务只配置Hibernate事务,那么对JDBC是否也有效?
2.如果上述情况无效,需要配置多个事务管理器,也就是说spring jdbc事务和hibernate各配置一个, 那么在同一个方法中,如果既用了hibernate,又用了spring jdbc 那么配置两个事务管理器,会不会有影响(如果只配置一个Hibernate是可以正常工作嘛)
3. 在一个事务方法中,如果开始另外一个线程去调用另外一个事务方法,是否构成嵌套事务??
2 楼
taya
2012-10-18
原来是这样的,谢谢分享。
我一直以为PROPAGATION_REQUIRED,即使是多个线程,也是同一事务。
有点想当然了。
我一直以为PROPAGATION_REQUIRED,即使是多个线程,也是同一事务。
有点想当然了。
1 楼
huang_yong
2012-04-14
引用
在相同线程中进行相互嵌套调用的事务方法工作于相同的事务中。如果这些相互嵌套调用的方法工作在不同的线程中,则不同线程下的事务方法工作在独立的事务中。
意思就是说:
在单线程环境下,A方法调用B方法,两个方法都在同一个事务中。
在多线程环境下,A方法调用B方法,两个方法各自具有各自的事务(两个事务)。
一句话:多线程肯定多事务,单线程一般都是单事务,也可以配置成多事务。
请问作者理解是否正确?
PS:
也可以使用 ThreadPoolTaskExecutor 开启一个线程
发表评论
-
一个常见的Spring IOC疑难症状
2013-07-25 14:14 4959Case 请看下面的IOC实例: 1)Aa ... -
mybatis3.1分页自动添加总数
2013-07-08 21:11 22711问题 1.mybatis默认分页是内存分页的,谁用谁崩溃啊! ... -
Rop开发手册(1):最简单的服务开放平台框架
2012-08-08 11:35 8497Rop概述 Rop是Rapid Open Pl ... -
学习Spring必学的Java基础知识(9)----HTTP请求报文
2012-06-09 16:02 13870引述要学习Spring框架的技术内幕,必须事先掌握一些基本的J ... -
学习Spring必学的Java基础知识(8)----国际化信息
2012-05-26 11:19 28272引述要学习Spring框架的 ... -
学习Spring必学的Java基础知识(7)----事务基础知识
2012-05-26 10:57 5034引述要学习Spring框架的技术内幕,必须事先掌握一些基本的J ... -
学习Spring必学的Java基础知识(6)----ThreadLocal
2012-05-19 10:09 12055引述要学习Spring框架的 ... -
学习Spring必学的Java基础知识(5)----注解
2012-05-19 09:56 5730引述要学习Spring框架的技术内幕,必须事先掌握一些基本的J ... -
学习Spring必学的Java基础知识(4)----XML基础知识
2012-05-12 15:33 8489引述要学习Spring框架的 ... -
学习Spring必学的Java基础知识(3)----PropertyEditor
2012-05-12 15:13 16762引述要学习Spring框架的 ... -
明明白白AOP(傻瓜也会心领神会!)
2012-05-05 11:04 10507引子: AOP(面向方面编 ... -
学习Spring必学的Java基础知识(2)----动态代理
2012-05-02 13:03 9619引述要学习Spring框架的 ... -
学习Spring必学的Java基础知识(1)----反射
2012-04-25 13:57 89570引述要学习Spring框架的技术内幕,必须事先掌握一些基本的J ... -
透透彻彻IoC(你没有理由不懂!)
2012-04-18 11:01 94050引述:IoC(控制反转:I ... -
单元测试系列之5:使用unitils测试Service层
2012-04-14 10:48 18331引述:Spring 的测试框架为我们提供一个强大的测试环境,解 ... -
如何用Spring读取JAR中的文件
2012-04-13 17:22 18290使用如下方式读取JAR中的文件出错 类路径下 ... -
单元测试系列之4:使用Unitils测试DAO层
2012-04-12 16:32 19580Spring 的测试框架为我们提供一个强大的测试环境,解 ... -
单元测试系列之3:测试整合之王Unitils
2012-04-09 14:11 15539引述:程序测试对保障应用程序正确性而言,其重要性怎么样强调都不 ... -
单元测试系列之2:模拟利器Mockito
2012-03-30 11:38 15178引述:程序测试对 ... -
单元测试系列之1:开发测试的那些事儿
2012-03-28 12:52 9959引述:程序测试对保障应用程序正确性而言,其重要性怎 ...
相关推荐
spring boot 纯注解方法事务控制回滚,注解+简单配置文件使用多线程demo
Spring事务管理Demo
Synchronized锁在Spring事务管理下,导致线程不安全。
Spring事务管理.pdf 1.资料 2.本地事务与分布式事务 3.编程式模型 4.宣告式模型
Spring事务管理教程,详细讲解了Spring中的事务管理,包括声明式事务,注解式事务,以及事务配置等等
Spring源代码解析(一):Spring中的事务处理 Spring源代码解析(二):ioc容器在Web容器中的启动 Spring源代码分析(三):Spring JDBC Spring源代码解析(四):Spring MVC Spring源代码解析(五):Spring AOP获取Proxy ...
酒店管理系统 功能点: 酒店管理,OTA直连 技术栈: 前端: react网页web框架,app 使用谷歌跨平台框架 flutter 后端: springcloud全家桶 项目名: 酒店管理系统 功能点: 酒店管理,OTA直连 技术栈: 前端: react...
spring 事务管理的理解
spring事务管理 配置文件等详解
spring事务操作试验 博客地址:https://blog.csdn.net/u010476739/article/details/99130972
Spring事务操作示例(四种方式),包含完整代码和数据库文件(基于MySQL,在项目sql文件夹中),可运行,学习Spring事务详见博客:http://blog.csdn.net/daijin888888/article/details/51822257
Spring事务管理4种方式 入门级 最简单demo PlatformTransactionManager TransactionTemplate
本代码使用H2内存数据库演示spring事务使用,包括编程式事务,声明式事务@Transactional使用,自定义事务事务注解实现自定义事务管理器
spring事务管理几种方式代码实例:涉及编程式事务,声明式事务之拦截器代理方式、AOP切面通知方式、AspectJ注解方式,通过不同方式实例代码展现,总结spring事务管理的一般规律,从宏观上加深理解spring事务管理特性...
Spring事务管理(全),需要的可下载!
Java高级编程 实验报告 spring 声明事务 实验目的 掌握spring 声明式事务管理配置 实验环境 本实验采用本实验采用的eclipse或者 Myeclpse开发工具。Spring 4.0以上 Jdk1.7以上、oracle/mysql。
在该JAR包的org.springframework.transaction包中,有3个接口文件PlatformTransactionManager、TransactionDefinition和TransactionStatus,如下图所示: Spring事务管理的三个核心接口 5.1.1 事务管理的核心接口 1....
4、了解Spring事务管理的两种方式; 5、掌握基于XML和Annotation的声明式事务管理的使用。 二.实验内容 (1)使用Spring JDBC实现书店的购书过程,即有如下一个BookShopDao接口,编写BookShopDaoImp类实现该接口中的...
全面分析_Spring_的编程式事务管理及声明式事务管理,本教程假定您已经掌握了 Java 基础知识,并对 Spring 有一定了解。您还需要具备基本的事务管理的知识,比如:事务的定义,隔离级别的概念,等等。本文将直接使用...