数据库创建两张表进行测试
mysql> create table student(id int , name varchar(50));
mysql> create table classroom(id int , name varchar(50));
首先写从数据库获取连接的ConnectionUtil.java
package com.zf.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public final class ConnectionUtil {
private final static String username = "root";
private final static String password = "root";
private final static String url = "jdbc:mysql:///threadlocal";
private ConnectionUtil(){
}
static{
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection openConnection(){
Connection conn = null ;
try {
conn = DriverManager.getConnection(url, username, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn ;
}
}
然后写管理Connection的SessionManager 类似于hibernate 的 SessionFactory
package com.zf.util;
import java.sql.Connection;
import java.sql.SQLException;
/**
* 单例实现
* @author zhoufeng
*
*/
public final class SessionManager {
private static ThreadLocal session = new ThreadLocal();
private static final SessionManager sessionManager = new SessionManager() ;
private SessionManager(){} ;
/**
* 在获取SessionManager时 ,就绑定Connection到ThreadLocal中
* @return
*/
public static SessionManager newInstance(){
try {
if(session.get() == null || session.get().isClosed()){
session.set(ConnectionUtil.openConnection()) ;
}
} catch (SQLException e) {
e.printStackTrace();
}
return sessionManager;
}
public Connection getCurrentSession(){
return session.get() ;
}
public void beginTransaction(){
try {
session.get().setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
public void rollback(){
try {
session.get().rollback() ;
session.get().close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void commit(){
try {
session.get().commit() ;
session.get().close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
然后是操作数据库两张表的Dao
package com.zf.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.zf.util.SessionManager;
public class ClassRoomDao {
public boolean addClassRoom(int id , String name) throws SQLException{
String sql = "insert into classroom values(? , ?)";
Connection conn = SessionManager.newInstance().getCurrentSession() ;
System.out.println(Thread.currentThread().getId() + " addClassRoom " + conn);
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, id);
ps.setString(2, name);
int count = ps.executeUpdate();
return count > 0 ;
}
}
package com.zf.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.zf.util.SessionManager;
public class StudentDao {
public boolean addStudent(int id , String name) throws SQLException{
String sql = "insert into student values(? , ?)";
Connection conn = SessionManager.newInstance().getCurrentSession() ;
System.out.println(Thread.currentThread().getId() + " addStudent " + conn);
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, id);
ps.setString(2, name);
int count = ps.executeUpdate();
return count > 0 ;
}
}
接下来就定义Service接口 并实现
package com.zf.service;
import java.sql.SQLException;
public interface SCService {
void addStudent(int id , String name) throws SQLException;
}
package com.zf.service;
import java.sql.SQLException;
import com.zf.dao.ClassRoomDao;
import com.zf.dao.StudentDao;
import com.zf.util.SessionManager;
public class SCServiceImpl implements SCService{
public void addStudent(int id , String name) throws SQLException{
StudentDao sd = new StudentDao() ;
ClassRoomDao cr = new ClassRoomDao() ;
sd.addStudent(id, name);
if(id > 8) //测试是否会回滚事务
throw new RuntimeException("my exception");
cr.addClassRoom(id, name);
}
}
package com.zf.util;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 用该类来代理Service , 为需要代理的Service加入事务 。
* 实现AOP事务管理
* @author zhoufeng
*
*/
public class ServiceFactory {
public static Object proxyService(final Object obj , final Class[] inf){
Object proxyService = Proxy.newProxyInstance(obj.getClass().getClassLoader(), inf , new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
SessionManager sm = SessionManager.newInstance();
Object result = null ;
try {
sm.beginTransaction() ;
result = method.invoke(obj, args);
sm.commit();
} catch (Exception e) {
sm.rollback();
e.printStackTrace();
}
return result;
}
}) ;
return proxyService ;
}
}
测试
package com.zf.test;
import java.sql.SQLException;
import com.zf.service.SCService;
import com.zf.service.SCServiceImpl;
import com.zf.util.ServiceFactory;
public class Test01 {
public static void main(String[] args) {
final SCService ss = (SCService) ServiceFactory.proxyService(new SCServiceImpl() , new Class[]{SCService.class});
/**
* 用两条线程分别执行service方法
* 结果会看到同一条线程中 各个Dao中获取的Connection是相同的
* 第二条线程发生了异常,并且事务回滚了
*/
new Thread(new Runnable() {
@Override
public void run() {
try {
ss.addStudent(8, "name8");
} catch (SQLException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
ss.addStudent(9, "name9");
} catch (SQLException e) {
e.printStackTrace();
}
}
}).start();
}
}