Hibernate事务

JDBCTransaction 

单个数据库(一个SesisonFactory对应一个数据库),由JDBC实现。

Java代码 复制代码  收藏代码
  1. Session session = null;   
  2. Transaction tx =null;   
  3. try {   
  4. session = sessionFactory.openSession();   
  5. tx = session.beginTransaction();//相当于JDBC的connection.setAutoCommit(false);   
  6. //process   
  7. tx.commit();//相当于JDBC的connection.commit();   
  8. catch(HibernateException e){   
  9. if(tx != null)tx.rollback();//相当于JDBC的connection.rollback();   
  10.                  throw e;   
  11. }finally {   
  12. if (session != null)session.close();   
  13. }  
Session session = null;
Transaction tx =null;
try {
session = sessionFactory.openSession();
tx = session.beginTransaction();//相当于JDBC的connection.setAutoCommit(false);
//process
tx.commit();//相当于JDBC的connection.commit();
} catch(HibernateException e){
if(tx != null)tx.rollback();//相当于JDBC的connection.rollback();
                 throw e;
}finally {
if (session != null)session.close();
}
  

JTATransaction(分布式事务,垮数据库,比如说银行转账,就需要这种跨数据库的事务来操作)

可以简单的理解成跨数据库的事物,由应用JTA 容器实现;使用JTATransaction需要配置hibernate.transaction.factory_class参数,该参数缺省值 是org.hibernate.transaction. JDBCTransactionFactory,当使用JTATransaction时需要将该参数改成org.hibernate.transaction.JTATransactionFactory,并配置jta.UserTransaction参数JNDI名(Hibernate在启动JTATransaction时要用该值到JNDI的上下文Context中去找javax.transaction.UserTransaction)。

Java代码 复制代码  收藏代码
  1. javax.transaction.UserTransactin tx = context.lookup(“jndiName”);   
  2. try{   
  3. tx.begin();   
  4. //多个数据库的session操作;   
  5. //session1….   
  6. //session2….   
  7. tx.commit();   
  8. }catch(Exception e){   
  9. tx.rollback();   
  10.         throw e;   
  11. }  
javax.transaction.UserTransactin tx = context.lookup(“jndiName”);
try{
tx.begin();
//多个数据库的session操作;
//session1….
//session2….
tx.commit();
}catch(Exception e){
tx.rollback();
        throw e;
}
 
session context和事务边界

事务边界:即事务开启,提交,关闭这些代码的位置。

mvc三层架构的思想上,事务边界的处理应该放在业务逻辑层中,但是Transaction对象是dao层的,所以要采用spring这种框架来实现明确的mvc分层。

Open session in view解决事务边界问题和数据懒加载问题。

Open session in view带来的问题:

session和transaction的时间延长。如果对数据加锁那就更长时间占用对象,session延长对内存的占用时间更长,对内存大小要求更大,且和数据库长时间交互,数据库的并发能力降低

 

 

current_session_context_class属性来定义context(用sessionFactory.getCurrentSession()来获得session),其值为:

1.thread:ThreadLocal来管理Session实现多个操作共享一个Session,避免反复获取Session,并控制事务边界,此时session不能调用close当commit或rollback的时候session会自动关闭(connection.release_mode:after_transaction)。Open session in view:在生成(渲染)页面时保持 session打开。

2.jta:由JTA事务管理器来管理事务(connection.release_mode:after_statement)。

用图理解:

从图中可以显示:客户端看到viewHTML时session还没有关闭,session要消息4后Filter中关闭。

把session的范围扩大到整个请求的范围内,这样在一方面很好的解决了懒加载session关闭的问题,另一方面一次请求变成了一个事务,那么用户做的更新操作对数据库来说都是一条sql语句了。

但是放大了session范围,如果网速比较慢,那么session就会一直打开,一级缓存的数据得不到释放,还有事务本应当在业务逻辑层开启关闭的,也放大到了整个请求。

code:

HibernateUtil.java

 

Java代码 复制代码  收藏代码
  1. package cn.itcast.hibernate;   
  2. import java.io.Serializable;   
  3. import org.hibernate.Session;   
  4. import org.hibernate.SessionFactory;   
  5. import org.hibernate.Transaction;   
  6. import org.hibernate.cfg.Configuration;   
  7. //工具类一般不需要更改,所以final   
  8. public final class HibernateUtil {   
  9.     private static SessionFactory sessionFactory;   
  10.     private static ThreadLocal session = new ThreadLocal();//把ThreadLocal当成一个Map容器   
  11.     //禁止别的类new   
  12.     private HibernateUtil() {   
  13.     }   
  14.   
  15.     static {   
  16.         Configuration cfg = new Configuration();   
  17.         cfg.configure();   
  18.         sessionFactory = cfg.buildSessionFactory();   
  19.     }   
  20.   
  21.     public static Session getThreadLocalSession() {   
  22.         Session s = (Session) session.get();//ThreadLocal的key是默认的,可以把key理解为当前线程   
  23.         if (s == null) {   
  24.             s = getSession();   
  25.             session.set(s);   
  26.         }   
  27.         return s;   
  28.     }   
  29.   
  30.     public static void closeSession() {   
  31.         Session s = (Session) session.get();   
  32.         if (s != null) {   
  33.             s.close();   
  34.             session.set(null);   
  35.         }   
  36.     }   
  37.   
  38.     public static SessionFactory getSessionFactory() {   
  39.         return sessionFactory;   
  40.     }   
  41. }  
package cn.itcast.hibernate;
import java.io.Serializable;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
//工具类一般不需要更改,所以final
public final class HibernateUtil {
	private static SessionFactory sessionFactory;
	private static ThreadLocal session = new ThreadLocal();//把ThreadLocal当成一个Map容器
    //禁止别的类new
	private HibernateUtil() {
	}

	static {
		Configuration cfg = new Configuration();
		cfg.configure();
		sessionFactory = cfg.buildSessionFactory();
	}

	public static Session getThreadLocalSession() {
		Session s = (Session) session.get();//ThreadLocal的key是默认的,可以把key理解为当前线程
		if (s == null) {
			s = getSession();
			session.set(s);
		}
		return s;
	}

	public static void closeSession() {
		Session s = (Session) session.get();
		if (s != null) {
			s.close();
			session.set(null);
		}
	}

	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}
}

 OpenSessionInView.java过滤器。负责从ThreadLocal中获得session和关闭session

 

Java代码 复制代码  收藏代码
  1. package com.taobao.hibernate;   
  2.   
  3. import java.io.IOException;   
  4. import javax.servlet.Filter;   
  5. import javax.servlet.FilterChain;   
  6. import javax.servlet.FilterConfig;   
  7. import javax.servlet.ServletException;   
  8. import javax.servlet.ServletRequest;   
  9. import javax.servlet.ServletResponse;   
  10. import org.hibernate.Session;   
  11. import org.hibernate.Transaction;   
  12.   
  13. public class OpenSessionInView implements Filter {   
  14.   
  15.     public void destroy() {   
  16.     }   
  17.   
  18.     public void doFilter(ServletRequest arg0, ServletResponse arg1,   
  19.             FilterChain arg2) throws IOException, ServletException {   
  20.         Session session = null;   
  21.         Transaction tx = null;   
  22.         try {   
  23.             session = HibernateUtil.getThreadLocalSession();   
  24.             tx = session.beginTransaction();   
  25.             arg2.doFilter(arg0, arg1);   
  26.             tx.commit();   
  27.         } catch (Exception e) {   
  28.             if (tx != null)   
  29.                 tx.rollback();   
  30.             throw new RuntimeException(e.getMessage(), e);   
  31.         } finally {   
  32.             HibernateUtil.closeSession();   
  33.         }   
  34.   
  35.     }   
  36.   
  37.     public void init(FilterConfig arg0) throws ServletException {   
  38.     }   
  39.   
  40. }  
package com.taobao.hibernate;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.hibernate.Session;
import org.hibernate.Transaction;

public class OpenSessionInView implements Filter {

	public void destroy() {
	}

	public void doFilter(ServletRequest arg0, ServletResponse arg1,
			FilterChain arg2) throws IOException, ServletException {
		Session session = null;
		Transaction tx = null;
		try {
			session = HibernateUtil.getThreadLocalSession();
			tx = session.beginTransaction();
			arg2.doFilter(arg0, arg1);
			tx.commit();
		} catch (Exception e) {
			if (tx != null)
				tx.rollback();
			throw new RuntimeException(e.getMessage(), e);
		} finally {
			HibernateUtil.closeSession();
		}

	}

	public void init(FilterConfig arg0) throws ServletException {
	}

}
 然后在业务层可以处理多个业务数据,在dao层获得过滤器打开的session处理数据和数据库的交互。

悲观锁和乐观锁

悲观锁由数据库来实现,从读取的时候开始加锁,直到修改完成。

缺点:读取完以后,用户修改过程缓慢,造成同步性降低。

乐观锁hibernate用version和timestamp来实现。两人同时编辑时候,假设获取的版本号都为1,编辑完提交的时候,版本号为2,第一个提交完以后,数据库版本号为2,第二个提交的时候对比版本号就会报错。 

code:

给Users加上版本号

Users.java

 

Java代码 复制代码  收藏代码
  1. import java.util.Date;     
  2.      
  3. public class Users {     
  4.     private int id;     
  5.     private String name;     
  6.     private Date birthday;     
  7.     private int ver;     
  8.          
  9.     public int getId() {     
  10.         return id;     
  11.     }     
  12.     public void setId(int id) {     
  13.         this.id = id;     
  14.     }     
  15.     public String getName() {     
  16.         return name;     
  17.     }     
  18.     public void setName(String name) {     
  19.         this.name = name;     
  20.     }     
  21.     public Date getBirthday() {     
  22.         return birthday;     
  23.     }     
  24.     public void setBirthday(Date birthday) {     
  25.         this.birthday = birthday;     
  26.     }     
  27.     public void setVer(int ver) {     
  28.         this.ver = ver;     
  29.     }     
  30.     public int getVer() {     
  31.         return ver;     
  32.     }     
  33. }    
import java.util.Date;  
  
public class Users {  
    private int id;  
    private String name;  
    private Date birthday;  
    private int ver;  
      
    public int getId() {  
        return id;  
    }  
    public void setId(int id) {  
        this.id = id;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public Date getBirthday() {  
        return birthday;  
    }  
    public void setBirthday(Date birthday) {  
        this.birthday = birthday;  
    }  
    public void setVer(int ver) {  
        this.ver = ver;  
    }  
    public int getVer() {  
        return ver;  
    }  
}  

 Users.hbm.xml

 

Xml代码 复制代码  收藏代码
  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC    
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"   
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.taobao.hibernate.domain">  
  6.     <class name="User">  
  7.         <id name="id">  
  8.             <generator class="native" />  
  9.         </id>  
  10.         <version name="ver"/><!--版本号,时间戳必须写在id后面--><!--也可以使用<timestamp name=""/>,但version标签可以铜鼓type指定不同类型-->  
  11.         <!-- <property name="name" /> -->  
  12.         <component name="name">  
  13.             <property name="firstName" column="first_name"/>  
  14.             <property name="lastName" column="last_name" />  
  15.         </component>  
  16.         <property name="birthday" />  
  17.     </class>  
  18. </hibernate-mapping>  
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.taobao.hibernate.domain">
	<class name="User">
		<id name="id">
			<generator class="native" />
		</id>
		<version name="ver"/><!--版本号,时间戳必须写在id后面--><!--也可以使用<timestamp name=""/>,但version标签可以铜鼓type指定不同类型-->
		<!-- <property name="name" /> -->
		<component name="name">
			<property name="firstName" column="first_name"/>
			<property name="lastName" column="last_name" />
		</component>
		<property name="birthday" />
	</class>
</hibernate-mapping>

 VersionTest.java

 

Java代码 复制代码  收藏代码
  1. package com.taobao.hibernate;   
  2.   
  3. import java.util.Date;   
  4.   
  5. import org.hibernate.HibernateException;   
  6. import org.hibernate.Session;   
  7. import org.hibernate.Transaction;   
  8.   
  9. import com.taobao.hibernate.domain.Name;   
  10. import com.taobao.hibernate.domain.User;   
  11.   
  12. public class VersionTest {   
  13.   
  14.     public static void main(String[] args) {   
  15.         User user = new User();   
  16.         user.setBirthday(new Date());   
  17.         Name n = new Name();   
  18.         n.setFirstName("firstName");   
  19.         n.setLastName("lastName");   
  20.         user.setName(n);   
  21.         // 111   
  22.         addUser(user);   
  23.         // System.out.println("id: " + user.getId());   
  24.         // 222   
  25.         System.out.println("1111111");   
  26.         update(user.getId());   
  27.     }   
  28.   
  29.     static void update(int id) {   
  30.         Session s1 = null;   
  31.         s1 = HibernateUtil.getSession();   
  32.         Transaction tx1 = s1.beginTransaction();   
  33.         User user1 = (User) s1.get(User.class, id);   
  34.   
  35.         Session s2 = HibernateUtil.getSession();   
  36.         Transaction tx2 = s2.beginTransaction();   
  37.         User user2 = (User) s2.get(User.class, id);   
  38.   
  39.         user1.getName().setFirstName("new1 firstName");   
  40.   
  41.         user2.getName().setFirstName("new2 firstName");   
  42.   
  43.         tx1.commit();   
  44.         tx2.commit();   
  45.   
  46.            
  47.   
  48.         s1.close();   
  49.         s2.close();   
  50.     }   
  51.   
  52.     static void addUser(User user) {   
  53.         Session s = null;   
  54.         Transaction tx = null;   
  55.         try {   
  56.             s = HibernateUtil.getSession();   
  57.             tx = s.beginTransaction();   
  58.             s.save(user);   
  59.             // 333   
  60.             // s.persist(user);   
  61.             Name n = new Name();   
  62.             n.setFirstName("firstName");   
  63.             n.setLastName("lastName");   
  64.             user.setName(n);   
  65.             user.setBirthday(new Date());   
  66.             tx.commit();   
  67.             user.setBirthday(new Date());   
  68.             tx = s.beginTransaction();   
  69.             tx.commit();   
  70.             // 444   
  71.         } catch (HibernateException e) {   
  72.             if (tx != null)   
  73.                 tx.rollback();   
  74.             throw e;   
  75.         } finally {   
  76.             if (s != null)   
  77.                 s.close();   
  78.         }   
  79.     }   
  80.   
  81.     static void addUser1(User user) {   
  82.         Session s = null;   
  83.         Transaction tx = null;   
  84.         try {   
  85.             s = HibernateUtil.getSession();   
  86.             tx = s.beginTransaction();   
  87.             s.save(user);   
  88.             tx.commit();   
  89.         } finally {   
  90.             if (s != null)   
  91.                 s.close();   
  92.         }   
  93.     }   
  94. }  
package com.taobao.hibernate;

import java.util.Date;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.taobao.hibernate.domain.Name;
import com.taobao.hibernate.domain.User;

public class VersionTest {

	public static void main(String[] args) {
		User user = new User();
		user.setBirthday(new Date());
		Name n = new Name();
		n.setFirstName("firstName");
		n.setLastName("lastName");
		user.setName(n);
		// 111
		addUser(user);
		// System.out.println("id: " + user.getId());
		// 222
		System.out.println("1111111");
		update(user.getId());
	}

	static void update(int id) {
		Session s1 = null;
		s1 = HibernateUtil.getSession();
		Transaction tx1 = s1.beginTransaction();
		User user1 = (User) s1.get(User.class, id);

		Session s2 = HibernateUtil.getSession();
		Transaction tx2 = s2.beginTransaction();
		User user2 = (User) s2.get(User.class, id);

		user1.getName().setFirstName("new1 firstName");

		user2.getName().setFirstName("new2 firstName");

		tx1.commit();
		tx2.commit();

		

		s1.close();
		s2.close();
	}

	static void addUser(User user) {
		Session s = null;
		Transaction tx = null;
		try {
			s = HibernateUtil.getSession();
			tx = s.beginTransaction();
			s.save(user);
			// 333
			// s.persist(user);
			Name n = new Name();
			n.setFirstName("firstName");
			n.setLastName("lastName");
			user.setName(n);
			user.setBirthday(new Date());
			tx.commit();
			user.setBirthday(new Date());
			tx = s.beginTransaction();
			tx.commit();
			// 444
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			throw e;
		} finally {
			if (s != null)
				s.close();
		}
	}

	static void addUser1(User user) {
		Session s = null;
		Transaction tx = null;
		try {
			s = HibernateUtil.getSession();
			tx = s.beginTransaction();
			s.save(user);
			tx.commit();
		} finally {
			if (s != null)
				s.close();
		}
	}
}
 拟两个线程同步操作,更新user

运行结果如下

Hibernate: insert into Users (ver, name, birthday) values (?, ?, ?)

Hibernate: select users0_.id as id0_0_, users0_.ver as ver0_0_, users0_.name as name0_0_, users0_.birthday as birthday0_0_ from Users users0_ where users0_.id=?

Hibernate: update Users set ver=?, name=?, birthday=? where id=? and ver=?

Hibernate: update Users set ver=?, name=?, birthday=? where id=? and ver=?

Exception in thread "main" org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [domain.Users#1]

第二个提交的事务内报错,数据库内字段修改为new2。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值