ThreadLocal 用于控制事务
1、封装一个从连接池获取Connection的工具类
import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class DataSourceUtils { private static DataSource dataSource = new ComboPooledDataSource(); private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); // 直接可以获取一个连接池 public static DataSource getDataSource() { return dataSource; } // 获取连接对象 public static Connection getConnection() throws SQLException { Connection con = tl.get(); if (con == null) { con = dataSource.getConnection(); tl.set(con); } return con; } // 开启事务 public static void startTransaction() throws SQLException { Connection con = getConnection(); if (con != null) { con.setAutoCommit(false); } } // 事务回滚 public static void rollback() throws SQLException { Connection con = getConnection(); if (con != null) { con.rollback(); } } // 提交并且 关闭资源及从ThreadLocall中释放 public static void commitAndRelease() throws SQLException { Connection con = getConnection(); if (con != null) { con.commit(); // 事务提交 con.close();// 关闭资源 tl.remove();// 从线程绑定中移除 } } // 关闭资源方法 public static void closeConnection() throws SQLException { Connection con = getConnection(); if (con != null) { con.close(); } } public static void closeStatement(Statement st) throws SQLException { if (st != null) { st.close(); } } public static void closeResultSet(ResultSet rs) throws SQLException { if (rs != null) { rs.close(); } } }
2、使用
servlet封装数据调用service
//order对象封装完毕 ProductService service = new ProductService(); service.submitOrder(order);
service调用dao层,并开启事务
public void submitOrder(Order order) { //2,3两步必须是保持同时保存成功 ProductDao dao = new ProductDao(); //开始开启事务 try { //1、开启事务 DataSourceUtils.startTransaction(); //2、调用dao存储order表数据的方法 dao.addOrders(order); //3、调用到存储orderItem表数据的方法 dao.addOrderItems(order); } catch (SQLException e) { try { //4、如果2,3两步其中一个出现异常则回归该事务 DataSourceUtils.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); } finally{ try { //5、最后关闭资源 DataSourceUtils.commitAndRelease(); } catch (SQLException e) { e.printStackTrace(); } } }
dao层做的就是存放数据到数据库,和上面的service层一样重要(注意看上面两个标红的方法,方法明细如下)
public void addOrders(Order order) throws SQLException { QueryRunner runner = new QueryRunner(); String sql = "insert into orders values(?,?,?,?,?,?,?,?)"; Connection conn = DataSourceUtils.getConnection(); runner.update(conn,sql, order.getOid(),order.getOrdertime(),order.getTotal(),order.getState(), order.getAddress(),order.getName(),order.getTelephone(),order.getUser().getUid()); } public void addOrderItems(Order order) throws SQLException { QueryRunner runner = new QueryRunner(); String sql = "insert into orderitem values(?,?,?,?,?)"; Connection conn = DataSourceUtils.getConnection(); List<OrderItem> orderItems = order.getOrderItems(); for(OrderItem item : orderItems){ runner.update(conn,sql,item.getItemid(),item.getCount(),item.getSubtotal(),item.getProduct().getPid(),
item.getOrder().getOid()); } } //上面两个方法获取的conn是同一个conn,因为用到了ThreadLocal所以才会出现同一个conn的效果
想了解ThreadLocal可以参考下面这篇文章:彻底理解ThreadLocal