十六、DBUtils事務使用
阿新 • • 發佈:2018-11-22
要保證QueryRunner操作事務時能夠生效就必須要儲存呼叫api時使用的Connection物件是同一個.為了減少程式碼的耦合性,這裡可以使用ThreadLocal類來綁定當前執行緒的Connection物件.
關於事務的操作以及Connection物件的唯一性操作可以寫到一個工具類中
package blog.csdn.net.mchenys.utils; 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 { // c3p0連線池 private static ComboPooledDataSource ds = new ComboPooledDataSource(); // 當前執行緒關聯的資料庫連線物件 private static ThreadLocal<Connection> tl = new ThreadLocal<>(); /** * 從執行緒中獲取連線 * * @return * @throws SQLException */ public static Connection getConnection() throws SQLException { // 從執行緒中獲取conneciton Connection conn = tl.get(); if (conn == null) { conn = ds.getConnection(); // 和當前執行緒繫結 tl.set(conn); } return conn; } /** * 取資料來源 * @return */ public static DataSource getDataSource() { return ds; } /** * 釋放資源 * @param st * @param rs */ public static void closeResource(Statement st, ResultSet rs) { closeResultSet(rs); closeStatement(st); } /** * 釋放資源 * @param conn * @param st * @param rs */ public static void closeResource(Connection conn, Statement st, ResultSet rs) { closeResource(st, rs); closeConn(conn); } /** * 釋放 connection * @param conn */ public static void closeConn(Connection conn) { if (conn != null) { try { conn.close(); // 和執行緒解綁 tl.remove(); } catch (SQLException e) { e.printStackTrace(); } conn = null; } } /** * 釋放 statement * @param st */ public static void closeStatement(Statement st) { if (st != null) { try { st.close(); } catch (SQLException e) { e.printStackTrace(); } st = null; } } /** * 釋放結果集 * @param rs */ public static void closeResultSet(ResultSet rs) { if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } rs = null; } } /** * 開啟事務 * @throws SQLException */ public static void startTransaction() throws SQLException { getConnection().setAutoCommit(false); } /** * 事務提交且釋放連線 */ public static void commitAndClose() { Connection conn = null; try { conn = getConnection(); // 事務提交 conn.commit(); // 關閉資源 conn.close(); // 解除繫結 tl.remove(); } catch (SQLException e) { e.printStackTrace(); } } /** * 事務回滾且釋放資源 */ public static void rollbackAndClose() { Connection conn = null; try { conn = getConnection(); // 事務回滾 conn.rollback(); // 關閉資源 conn.close(); // 解除版定 tl.remove(); } catch (SQLException e) { e.printStackTrace(); } } }
下面以新增訂單和訂單項的操作為例演示下在dbutils下的事務事務使用步驟.
需求:提供一個方法生成一條訂單,該訂單可以包含有多個訂單項,當訂單或者訂單項添加出錯的時候回滾所有操作,必須要等這2個操作都完成才算生成訂單成功.
Service層操作
package blog.csdn.net.mchenys.service.impl; import java.sql.SQLException; import java.util.List; import java.util.Map; import org.apache.commons.beanutils.BeanUtils; import blog.csdn.net.mchenys.dao.OrderDao; import blog.csdn.net.mchenys.dao.impl.OrderDaoImpl; import blog.csdn.net.mchenys.domain.Order; import blog.csdn.net.mchenys.domain.OrderItem; import blog.csdn.net.mchenys.domain.PageBean; import blog.csdn.net.mchenys.domain.Product; import blog.csdn.net.mchenys.service.OrderService; import blog.csdn.net.mchenys.utils.DataSourceUtils; /** * 訂單模組 * * @author mChenys * */ public class OrderServiceImpl implements OrderService { .... // 新增訂單 public void add(Order order) throws Exception { try { // 開啟事務 DataSourceUtils.startTransaction(); OrderDao dao = new OrderDaoImpl(); // 新增一條訂單記錄 dao.add(order); // 新增多條訂單項記錄 for (OrderItem item : order.getItems()) { dao.addItem(item); } // 完成事務 DataSourceUtils.commitAndClose(); } catch (SQLException e) { e.printStackTrace(); // 回滾事務 DataSourceUtils.rollbackAndClose(); throw e; } } .... }
DAO層操作
package blog.csdn.net.mchenys.dao.impl; import java.util.List; import java.util.Map; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import org.apache.commons.dbutils.handlers.MapListHandler; import org.apache.commons.dbutils.handlers.ScalarHandler; import blog.csdn.net.mchenys.dao.OrderDao; import blog.csdn.net.mchenys.domain.Order; import blog.csdn.net.mchenys.domain.OrderItem; import blog.csdn.net.mchenys.utils.DataSourceUtils; public class OrderDaoImpl implements OrderDao { .... @Override public void add(Order order) throws Exception { // 手動管理事務則不能通過構造方法傳入connection QueryRunner qr = new QueryRunner(); String sql = "insert into orders values(?,?,?,?,?,?,?,?)"; // connection需要保持同一個.從DataSourceUtils中獲取 qr.update(DataSourceUtils.getConnection(), sql, order.getOid(), order.getOrdertime(), order.getTotal(), order.getState(), order.getAddress(), order.getName(), order.getTelephone(), order.getUser().getUid()); } @Override public void addItem(OrderItem orderItem) throws Exception { // 手動管理事務,connection需要保持同一個.從DataSourceUtils中獲取 QueryRunner qr = new QueryRunner(); String sql = "insert into orderitem values(?,?,?,?,?)"; qr.update(DataSourceUtils.getConnection(), sql, orderItem.getItemid(), orderItem.getCount(), orderItem.getSubtotal(), orderItem.getProduct().getPid(), orderItem.getOrder().getOid()); } .... }