都必须 new 一个新的实例。传统的 Service 由于将有状态的 DAO 作为成员变量,所以传统的 Service 本身也是有状态的。
但是在 Spring 中,DAO 和 Service 都以单实例的方式存在。Spring 是通过 ThreadLocal 将有状态的变量(如 Connection 等)本地线程化,达到另一个层面上的“线程无关”,从而 实现线程安全。Spring 不遗余力地将状态化的对象无状态化,就是要达到单实例化 Bean 的目 的。
由于 Spring 已经通过 ThreadLocal 的设施将 Bean 无状态化,所以 Spring 中单实例 Bean 对线程安全问题拥有了一种天生的免疫能力。不但单实例的 Service 可以成功运行于多 线程环境中,Service 本身还可以自由地启动独立线程以执行其它的 Service。下面,通过一 个实例对此进行描述:
清单 13 UserService.java 在事务方法中启动独立线程运行另一个事务方法
@Service("userService")
public class UserService extends BaseService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private ScoreService scoreService;
//① 在logon方法体中启动一个独立的线程,在该独立的线程中执行 ScoreService#addScore()方法
public void logon(String userName) {
System.out.println("logon method...");
updateLastLogonTime(userName);
Thread myThread = new MyThread(this.scoreService,userName,20);
myThread.start();
}
public void updateLastLogonTime(String userName) {
System.out.println("updateLastLogonTime...");
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() {
scoreService.addScore(userName,toAdd);
}
}
}
Spring事务管理高级应用难点剖析,第1部分(12)
时间:2012-04-26 IBM 陈雄华
将日志级别设置为 DEBUG,执行 UserService#logon() 方法,观察以下输出的日志:
清单 14 执行日志
[main] (AbstractPlatformTransactionManager.java:365) - Creating new transaction with name
[user.multithread.UserService.logon]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT ①
[main] (DataSourceTransactionManager.java:205) - Acquired Connection
[org.apache.commons.dbcp.PoolableConnection@1353249] for JDBC transaction
logon method...
updateLastLogonTime...
[main] (JdbcTemplate.java:785) - Executing prepared SQL update
[main] (JdbcTemplate.java:569) - Executing prepared SQL statement
[UPDATE t_user u SET u.last_logon_time = ? WHERE user_name =?]
[main] (JdbcTemplate.java:794) - SQL update affected 0 rows
[main] (AbstractPlatformTransacti
|