jdbc的事物管理与ThreadLocale
来源:互联网 发布:php 创建二维码ticket 编辑:程序博客网 时间:2024/06/06 00:41
CREATE TABLE `account` ( `id` int(11) NOT NULL auto_increment, `name` varchar(40) default NULL, `money` float default NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8
数据连接池代码:
public class JdbcUtils{private static ComboPooledDataSource ds;static{ds = new ComboPooledDataSource();}public static DataSource getDataSource(){return ds;}public static Connection getConnection() throws Exception{return ds.getConnection();}}
在没有涉及事务的时候 从aa 转到bb的时候是dao这样子实现的:
public class AccountDao{public Account find(int id){try{QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());String sql = "select * from account where id=?";return (Account) qr.query(JdbcUtils.getConnection(),sql,id, new BeanHandler(Account.class));}catch (Exception e) {throw new RuntimeException(e);}}}public void update(Account a){try{QueryRunner qr=new QueryRunner(JdbcUtils.getDataSource());String sql="update account set money=? where id=?";Object []params={a.getMoney(),a.getId()};qr.update(JdbcUtils.getConnection(),sql,params);} catch (Exception e){throw new RuntimeException(e);}}
在执行service的时候 是2个不同的connction 根本无法执行事务:
AccountDao dao = new AccountDao();Account a = dao.find(sourceid);Account b = dao.find(targetid);a.setMoney(a.getMoney()-money);b.setMoney(b.getMoney()+money);dao.update(a); //sqldao.update(b); //sql
于是就这样子解决,但是dao只负责实现增删改查的功能具体实现交个servic去实现
public void transfer(){QueryRunner qr = new QueryRunner();Connection conn = null;try{conn = JdbcUtils.getConnection();conn.setAutoCommit(false);String sql1 = "update account set money=money-100 where name='aaa'";qr.update(conn, sql1);String sql2 = "update account set money=money+100 where name='bbb'";qr.update(conn, sql2);conn.commit();} catch (Exception e){try{conn.rollback();conn.commit();} catch (Exception e2){}throw new RuntimeException(e);} finally{try{conn.close();} catch (SQLException e){e.printStackTrace();}}}
此时为了统一connection就必须指定connection 在构造方法中添加了connection 使用dao 的时候就可以避免connection 的不统一
public class AccountDao{private Connection conn;public AccountDao(){}public AccountDao(Connection conn){this.conn=conn;}public Account find(int id){try{QueryRunner qr=new QueryRunner();String sql="select * from account where id=?";return (Account)qr.query(conn, sql,id, new BeanHandler(Account.class));} catch (Exception e){throw new RuntimeException(e);}}public void update(Account a){try{QueryRunner qr = new QueryRunner();String sql = "update account set money=? where id=?";Object[] params ={ a.getMoney(), a.getId() };qr.update(conn, sql, params);} catch (Exception e){throw new RuntimeException(e);}}}
此时统一 的connection就可以对事务进行操作
public void transfer(int sourceid,int targetid,double money) throws SQLException{Connection conn = null;try{conn = JdbcUtils.getConnection();conn.setAutoCommit(false);AccountDao dao = new AccountDao(conn);Account a = dao.find(sourceid);Account b = dao.find(targetid);a.setMoney(a.getMoney()-money);b.setMoney(b.getMoney()+money);dao.update(a); //sqldao.update(b); //sqlconn.commit();}catch (Exception e) {conn.rollback();conn.commit();}finally{conn.close();}}
构造方法中添加了connection 使用dao 的时候就可以避免connection 的不统一 但是这样子并不是很好就要使用了ThreadLocale
以前没有spring的最佳事务处理方法就是使用ThreadLocaled绑定数据 翻译局部线程 其实是它是一个容器存数据 当数据链接就和当前对象绑定了 无论去到哪儿都是同一个对象了
让线程绑定链接 所有操作都是一个链接上conntion
容器内部维护的是一个map集合 就是ThreadLocale(map,关键字就是当前线程的id 当threadLocale get的时候根据id得到就是绑定的链接
重新修改jdbcutils
public class JdbcUtils{private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();private static ComboPooledDataSource ds;static{ds = new ComboPooledDataSource();}public static DataSource getDataSource(){return ds;}public static Connection getConnection() throws Exception{Connection conn = tl.get();return conn;}// 开始事物public static void startTransaction(){try{Connection conn = tl.get();if (conn == null){conn = ds.getConnection();tl.set(conn);}conn.setAutoCommit(false);} catch (Exception e){throw new RuntimeException(e);}}// 提交事物public static void commitTransaction(){try{Connection conn = tl.get();if (conn != null){conn.commit();}} catch (Exception e){throw new RuntimeException(e);}}public static void rollbackTransaction(){try{Connection conn = tl.get();if (conn != null){conn.rollback();conn.commit();}} catch (Exception e){throw new RuntimeException(e);}}public static void closeConenction(){try{Connection conn = tl.get();if (conn != null){try{conn.close();} finally{tl.remove();// 切忌这句话不能少}}} catch (Exception e){throw new RuntimeException(e);}}}
dao就可以这样子的去实现
public Account find(int id){try{QueryRunner qr=new QueryRunner();String sql="select * from account where id=?";return (Account)qr.query(JdbcUtils.getConnection(), sql,id, new BeanHandler(Account.class));} catch (Exception e){throw new RuntimeException(e);}}public void update(Account a){try{QueryRunner qr=new QueryRunner();String sql="update account set money=? where id=?";Object []params={a.getMoney(),a.getId()};qr.update(JdbcUtils.getConnection(),sql,params);} catch (Exception e){throw new RuntimeException(e);}
ThreadLocale的service这样子实现
//TreadLocalpublic void transfer(int sourceid,int targetid,double money) throws SQLException{AccountDao dao = new AccountDao();try{JdbcUtils.startTransaction(); //向当前线程上绑定一个开启事务的链接Account a = dao.find(sourceid);Account b = dao.find(targetid);a.setMoney(a.getMoney()-money);b.setMoney(b.getMoney()+money);dao.update(a); //sqldao.update(b); //sqlJdbcUtils.commitTransaction();}catch (Exception e) {JdbcUtils.rollbackTransaction();throw new RuntimeException(e);}finally{JdbcUtils.closeConnection();}}
注意事项:使用ThreadLcale线程范围内共享数据 线程内数据共享完后调关闭方法移除绑定 因为作为全局的使用 不移除 这个容器慢慢增加就出现内存溢出
另外就是事物边界提前了 当servlet调用service的时候完成后有请求转发到其他jsp页面上了而jsp页面又通过servlet调用了其他的service 这个时候就是事物边界提前了 从图中只能保证2个dao实现事务处理不能保证4个dao实现事务处理
就要用filter 维护里全局的ThreadLocale 当发现请求来了 ThreadLocale 绑定链接
filter做事务管理
- jdbc的事物管理与ThreadLocale
- JDBC的事物管理
- Hibernate与JDBC事物的混用
- 传智播客---什么是JDBC事物管理与数据库连接池
- JDBC数据库连接与事物
- 《Java》-------用AOP思想实现JDBC事物的管理
- JDBC的事物处理
- JDBC事物的使用
- spring 与 事物管理
- 33.1 JDBC技术与事物
- 事物<一> JDBC事物的理解
- 使用反射的方法实现JDBC数据库连接与事物
- hibernate 用spring实现jdbc事物管理
- Spring的事物管理
- Spring的事物管理
- 数据库的事物管理
- spring的事物管理
- JDBC的事物隔离级别
- 解析HTTP报文头
- 浅谈Util包中的List
- 在所有的文件的右键菜单中加入快捷命令“查找目标...”
- Android 国际化与资源自适应
- 指向指针的指针
- jdbc的事物管理与ThreadLocale
- cx_Oracle的配置啊。。终于搞出来了
- SocketProgram - Introduction
- Visual Studio 2010中VC++ Directories的设置
- 在Visual Studio 2010中使用Visual Leak Detector
- 麻省:计算机科学及编程导论——让学生培养计算式思维能力,并通过编程实现一些实用目的
- 好好学c++ gcc了
- 思考--中国为什么没有什么国际IT领头大企业
- IT业的未来主导将是软件业