【Hibernate系列】(二):事務的應用
阿新 • • 發佈:2019-02-09
需求
新增訂單成功後,需要將購物車中的商品清空,這兩個操作要麼都執行,要麼都不執行。這時,就用到了事務。
使用
1.配置
在hibernate.cfg.xml中新增
<!--使用currentSession配置事務-->
<property name="hibernate.current_session_context_class">thread</property>
2.開啟,關閉,回滾
/** 新增訂單資訊 **/
public Boolean addOrders(SchoolShop_Orders orders,int [] cids) {
Boolean flag = true;
Session session=getSession();
try {
//開啟事務
session.beginTransaction();
//新增訂單
session.save(orders);
//清空購物項
deleteCarts(cids,session);
//提交事務
session.getTransaction().commit();
} catch (Exception e) {
flag = false;
e.printStackTrace();
//回滾事務
session.getTransaction().rollback();
}
return flag;
}
/**
* 批量刪除購物項
* @param cids
* @param session
* @return
*/
public Boolean deleteCarts (int[] cids,Session session) {
int num=0;
String hql = "";
for(int i=0;i<cids.length;i++) {
if(i==0) {
hql = "cid="+cids[i];
} else {
hql =hql + " or cid="+cids[i];
}
}
Query q= session.createQuery("delete from SchoolShop_cart where "+hql);
num=q.executeUpdate();
if(num>0){
return true;
}else{
return false;
}
}
3.getSession方法
@Transactional
@SuppressWarnings("unchecked")
public class DaoSupportImpl<T> implements DaoSupport<T> {
@Resource
private SessionFactory sessionFactory;
private Class<T> clazz;
public DaoSupportImpl() {
// 使用反射技術得到T的真實型別
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); // 獲取當前new的物件的 泛型的父類 型別
this.clazz = (Class<T>) pt.getActualTypeArguments()[0]; // 獲取第一個型別引數的真實型別
System.out.println("clazz ---> " + clazz);
}
/**
* 獲取當前可用的Session
*
* @return
*/
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
}
問題
【錯誤】:WARN JDBCExceptionReporter:233 - SQL Error: 1205, SQLState: 41000
org.hibernate.exception.GenericJDBCException: could not execute update query16:05:37,361
【原因】:鎖等待超時
【解決】:事務範圍內,出現異常時,事務提交不成功,沒有回滾事務,所以必須加上session.getTransaction().rollback();
溫故
看看在不使用Hibernate框架的時候如何使用事務:
public void addFlowCard(FlowCard flowCard) throws ApplicationException {
Connection conn=null;
try{
conn = ConnectionManager.getConnection();
//開始事務
ConnectionManager.beginTransaction(conn);
String flowCardVouNo=flowCardDao.generateVouNo();
flowCardDao.addFlowCardMaster(flowCardVouNo, flowCard);
flowCardDao.addFlowCardDetail(flowCardVouNo, flowCard.getFlowCardDetailList());
//提交事務
ConnectionManager.commitTransaction(conn);
}catch(DaoException e){
//回滾事務
ConnectionManager.rollbackTransaction(conn);
throw new ApplicationException("新增流向單失敗!");
}finally{
//關閉Connection並從ThreadLocal中清除
ConnectionManager.closeConnection();
}
}
知新
對比使用Hibernate框架和不使用框架的情況下,事務的使用方法有何不同。發現,基本步驟沒有變(開啟事務,提交事務,回滾事務)。不同的是:
- 獲取連線物件的方式
不使用Hibernate的時候,藉助ThreadLocal獲得執行緒內的Connection物件:
package com.tgb.drp.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class ConnectionManager {
private static ThreadLocal<Connection> connectionHolder=new ThreadLocal<Connection>();
/**
* 獲得Connection
* @return
*/
public static Connection getConnection(){
Connection conn=connectionHolder.get();
if(conn==null){
try{
JdbcConfig jdbcConfig=XmlConfigReader.getInstance().getJdbcConfig();
Class.forName(jdbcConfig.getDriverName());
conn= DriverManager.getConnection(jdbcConfig.getUrl(),jdbcConfig.getUsername(),jdbcConfig.getPassword()) ;
connectionHolder.set(conn);
}catch (ClassNotFoundException e){
e.printStackTrace();
throw new ApplicationException("系統錯誤,請聯絡管理員!");
} catch (SQLException e) {
e.printStackTrace();
throw new ApplicationException("系統錯誤,請聯絡管理員!");
}
}
return conn;
}
/**
* 關閉Connection
*/
public static void closeConnection(){
Connection conn = connectionHolder.get();
if (conn != null) {
try {
conn.close();
//從ThreadLocal中清除Connection
connectionHolder.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 開始事務
* @param conn
*/
public static void beginTransaction(Connection conn) {
try {
if (conn != null) {
if (conn.getAutoCommit()) {
conn.setAutoCommit(false); //手動提交
}
}
}catch(SQLException e) {}
}
/**
* 提交事務
* @param conn
*/
public static void commitTransaction(Connection conn) {
try {
if (conn != null) {
if (!conn.getAutoCommit()) {
conn.commit();
}
}
}catch(SQLException e) {}
}
/**
* 回滾事務
* @param conn
*/
public static void rollbackTransaction(Connection conn) {
try {
if (conn != null) {
if (!conn.getAutoCommit()) {
conn.rollback();
}
}
}catch(SQLException e) {}
}
/**
* 關閉命令
* @param pstmt
*/
public static void close(Statement pstmt) {
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(ResultSet rs ) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
2.是否顯示的開啟和關閉連線物件
使用Hibernate的currensession時,並不需要我們自己去開啟或關閉物件。
所以使用Hibernate框架的好處在於框架幫我們封裝好了一些東西,讓我們儘可能少的關心資料庫,減少重複程式碼的編寫。