一、简单介绍ThreadLocal
ThreadLocal不是为了解决多线程访问共享变量,而是为每个线程创建一个单独的变量副本,提供了保持对象的方法和避免参数传递的复杂性。官方定义如下:
This class provides thread-local variables. These variables differ from their normal counterparts in hat each thread that accesses one (via its {@code get} or {@code set} method) has its own, independently initialized copy of the variable. {@code ThreadLocal} instances are typically private static fields in classes that wish to associate state with a thread (e.g.,a user ID or Transaction ID).大体翻译如下:
ThreadLocal类用来提供线程内部的局部变量。这些变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量,ThreadLocal实例通常来说都是private static类型。
ThreadLocal类的基本方法:
(1) void set(Object value)设置当前线程的线程局部变量的值。
(2) public Object get()该方法返回当前线程所对应的线程局部变量。
(3) public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。
需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
(4) protected Object initialValue()返回该线程局部变量的初始值。
二、Hibernate的事务处理
在Hibernate中,如果使用openSession()方法获取的session,每次创建的session都是不一样的,为了保证线程从创建Session到业务的彻底完成之前,自始至终都是同一个session,可以把session对象保存到ThreadLocal中。使用该方法openSession()在查询时,可以使用事务管理,也可以不使用事务管理,但是在添加、删除、修改时,必须使用事务管理,代码类似如下:
public List<T> getList(String hql){
Session session = getSession() ;
Transaction tx=session.beginTransaction();
Query query=session.createQuery(hql);
List<T> lis=null;
try {
lis = query.list();
tx.commit();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
tx.rollback();;
}
return lis;
}
public boolean Save(T obj){
Session session = getSession() ;
Transaction tx=session.beginTransaction();
boolean mark=true;
try {
session.save(obj);
tx.commit();
} catch (Exception e) {
// TODO Auto-generated catch block
mark=false;
e.printStackTrace();
tx.rollback();
}
return mark;
}
public boolean update(T obj){
Session session = getSession() ;
Transaction tx=session.beginTransaction();
boolean mark=true;
try {
session.saveOrUpdate(obj);
tx.commit();
} catch (Exception e) {
// TODO Auto-generated catch block
mark=false;
e.printStackTrace();
tx.rollback();
}
return mark;
}
@SuppressWarnings("unchecked")
public T getObjectById(int id,Class<T> c){
Session session = getSession() ;
Transaction tx=session.beginTransaction();
T obj=null;
try {
obj = (T) session.get(c, id);
tx.commit();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
tx.rollback();
}
return obj ;
}
public boolean delete(T obj){
Session session = getSession() ;
Transaction tx=session.beginTransaction();
boolean mark=true;
try {
session.delete(obj);
tx.commit();
} catch (Exception e) {
// TODO Auto-generated catch block
mark=false;
e.printStackTrace();
tx.rollback();
}
return mark;
}
三、使用JDK动态代理实现Hibernate的事务管理
需要注意的是,只有是同一个Session对象,事务管理才是有效的,这也说明,为什么在本例中,使用ThreadLocal来装载Session对象。
3.1 先定义一个接口
package cn.com.bochy.iuntil;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Configuration;
public interface IHibernate<T> {
public void rebuildSessionFactory() ;
public void closeSession() throws HibernateException ;
public org.hibernate.SessionFactory getSessionFactory() ;
public Configuration getConfiguration() ;
public List<T> getList(String hql);
public boolean Save(T obj);
public boolean update(T obj);
public T getObjectById(int id,Class<T> c);
public boolean delete(T obj);
public List<T> Page(String hql,int pageIndex,int pageSize);
}
这个接口就是说明代理类和被代理类之间共同的“任务”,是他们之间规范和协议。
3.2 接口的实现类
package cn.com.bochy.until;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import cn.com.bochy.iuntil.IHibernate;
public class HibernateUtilImpl<T> implements IHibernate<T> {
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static org.hibernate.SessionFactory sessionFactory;
private static Configuration configuration = new Configuration();
private static ServiceRegistry serviceRegistry;
static {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings
(configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
public HibernateUtilImpl() {
}
public Session getSession() throws HibernateException {
Session session = threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
public void rebuildSessionFactory() {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings
(configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
public void closeSession() throws HibernateException {
Session session = getSession() ;
threadLocal.set(null);
if (session != null) {
session.close();
}
}
public org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
public Configuration getConfiguration() {
return configuration;
}
@SuppressWarnings("unchecked")
public List<T> getList(String hql){
Session session = getSession() ;
Query query=session.createQuery(hql);
List<T> lis=null;
lis = query.list();
return lis;
}
public boolean Save(T obj){
Session session = getSession() ;
boolean mark=true;
try {
session.save(obj);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
mark=false;
}
return mark;
}
public boolean update(T obj){
Session session = getSession() ;
boolean mark=true;
try {
session.saveOrUpdate(obj);
} catch (Exception e) {
// TODO Auto-generated catch block
mark=false;
e.printStackTrace();
}
return mark;
}
@SuppressWarnings("unchecked")
public T getObjectById(int id,Class<T> c){
Session session = getSession() ;
T obj=null;
try {
obj = (T) session.get(c, id);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj ;
}
public boolean delete(T obj){
Session session = getSession() ;
boolean mark=true;
try {
session.delete(obj);
} catch (Exception e) {
// TODO Auto-generated catch block
mark=false;
e.printStackTrace();
}
return mark;
}
/**
* 分页
*/
@SuppressWarnings("unchecked")
public List<T> Page(String hql,int pageIndex,int pageSize){
Session session = getSession() ;
List<T> lis=null;
try {
Query query=session.createQuery(hql);
query.setFirstResult((pageIndex-1)*pageSize);
query.setMaxResults(pageSize);
lis = query.list();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return lis;
}
}
在这个类中,封装了Hibernate的DAO中最常见的业务:查询、修改、添加、删除、分页等,但是在这个封装类中没有用到事务处理。
3.3 定义代理类相关的处理类
package cn.com.bochy.hander;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.hibernate.Session;
import org.hibernate.Transaction;
import cn.com.bochy.until.HibernateUtilImpl;
//与代理类相关的处理类
public class Hander implements InvocationHandler{
private HibernateUtilImpl<?> Util;//被代理类对象
public Hander(HibernateUtilImpl<?> o){
this.Util=o;//通过构造方法给被代理对象赋值
}
@Override
//Object proxy:代理对象
//Method method:被代理对象的主业务逻辑的方法
//Object[] args:上述方法的参数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Session session = Util.getSession();
Transaction tx=session.beginTransaction();
Object o1=null;
try {
o1=method.invoke(Util, args);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}
return o1;
}
//得到代理对象
public Object getProxy(){
//ClassLoader loader:类加载器
//Class<?>[] interfaces:代理类的实现接口
//InvocationHandler h:与代理对象相关的处理对象
//生成一个被代理对象object的代理对象
return Proxy.newProxyInstance(Util.getClass().getClassLoader(),
Util.getClass().getInterfaces(), this);
}
}
在这个处理类中,统一对Hibernate的DAO中最常见的业务的进行了事务处理。
3.4 测试
package cn.com.bochy.test;
import cn.com.bochy.entity.Stu;
import cn.com.bochy.hander.Hander;
import cn.com.bochy.iuntil.IHibernate;
import cn.com.bochy.until.HibernateUtilImpl;
public class TestProxy {
public static void main(String[] args) {
Hander hander=new Hander(new HibernateUtilImpl<Stu>());
Object proxy=hander.getProxy();
@SuppressWarnings("unchecked")
IHibernate<Stu> s=(IHibernate<Stu>)proxy;
System.out.println(s.getList("from Stu").size());
Stu s1=new Stu();
s1.setName("chen2");
s.Save(s1);
}
}
如果学生s1已经存入数据库,则说明事务管理有效。
ThreadLocal不是为了解决多线程访问共享变量,而是为每个线程创建一个单独的变量副本,提供了保持对象的方法和避免参数传递的复杂性。官方定义如下:
This class provides thread-local variables. These variables differ from their normal counterparts in hat each thread that accesses one (via its {@code get} or {@code set} method) has its own, independently initialized copy of the variable. {@code ThreadLocal} instances are typically private static fields in classes that wish to associate state with a thread (e.g.,a user ID or Transaction ID).大体翻译如下:
ThreadLocal类用来提供线程内部的局部变量。这些变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量,ThreadLocal实例通常来说都是private static类型。
ThreadLocal类的基本方法:
(1) void set(Object value)设置当前线程的线程局部变量的值。
(2) public Object get()该方法返回当前线程所对应的线程局部变量。
(3) public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。
需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
(4) protected Object initialValue()返回该线程局部变量的初始值。
二、Hibernate的事务处理
在Hibernate中,如果使用openSession()方法获取的session,每次创建的session都是不一样的,为了保证线程从创建Session到业务的彻底完成之前,自始至终都是同一个session,可以把session对象保存到ThreadLocal中。使用该方法openSession()在查询时,可以使用事务管理,也可以不使用事务管理,但是在添加、删除、修改时,必须使用事务管理,代码类似如下:
public List<T> getList(String hql){
Session session = getSession() ;
Transaction tx=session.beginTransaction();
Query query=session.createQuery(hql);
List<T> lis=null;
try {
lis = query.list();
tx.commit();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
tx.rollback();;
}
return lis;
}
public boolean Save(T obj){
Session session = getSession() ;
Transaction tx=session.beginTransaction();
boolean mark=true;
try {
session.save(obj);
tx.commit();
} catch (Exception e) {
// TODO Auto-generated catch block
mark=false;
e.printStackTrace();
tx.rollback();
}
return mark;
}
public boolean update(T obj){
Session session = getSession() ;
Transaction tx=session.beginTransaction();
boolean mark=true;
try {
session.saveOrUpdate(obj);
tx.commit();
} catch (Exception e) {
// TODO Auto-generated catch block
mark=false;
e.printStackTrace();
tx.rollback();
}
return mark;
}
@SuppressWarnings("unchecked")
public T getObjectById(int id,Class<T> c){
Session session = getSession() ;
Transaction tx=session.beginTransaction();
T obj=null;
try {
obj = (T) session.get(c, id);
tx.commit();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
tx.rollback();
}
return obj ;
}
public boolean delete(T obj){
Session session = getSession() ;
Transaction tx=session.beginTransaction();
boolean mark=true;
try {
session.delete(obj);
tx.commit();
} catch (Exception e) {
// TODO Auto-generated catch block
mark=false;
e.printStackTrace();
tx.rollback();
}
return mark;
}
三、使用JDK动态代理实现Hibernate的事务管理
需要注意的是,只有是同一个Session对象,事务管理才是有效的,这也说明,为什么在本例中,使用ThreadLocal来装载Session对象。
3.1 先定义一个接口
package cn.com.bochy.iuntil;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Configuration;
public interface IHibernate<T> {
public void rebuildSessionFactory() ;
public void closeSession() throws HibernateException ;
public org.hibernate.SessionFactory getSessionFactory() ;
public Configuration getConfiguration() ;
public List<T> getList(String hql);
public boolean Save(T obj);
public boolean update(T obj);
public T getObjectById(int id,Class<T> c);
public boolean delete(T obj);
public List<T> Page(String hql,int pageIndex,int pageSize);
}
这个接口就是说明代理类和被代理类之间共同的“任务”,是他们之间规范和协议。
3.2 接口的实现类
package cn.com.bochy.until;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import cn.com.bochy.iuntil.IHibernate;
public class HibernateUtilImpl<T> implements IHibernate<T> {
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static org.hibernate.SessionFactory sessionFactory;
private static Configuration configuration = new Configuration();
private static ServiceRegistry serviceRegistry;
static {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings
(configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
public HibernateUtilImpl() {
}
public Session getSession() throws HibernateException {
Session session = threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
public void rebuildSessionFactory() {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings
(configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
public void closeSession() throws HibernateException {
Session session = getSession() ;
threadLocal.set(null);
if (session != null) {
session.close();
}
}
public org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
public Configuration getConfiguration() {
return configuration;
}
@SuppressWarnings("unchecked")
public List<T> getList(String hql){
Session session = getSession() ;
Query query=session.createQuery(hql);
List<T> lis=null;
lis = query.list();
return lis;
}
public boolean Save(T obj){
Session session = getSession() ;
boolean mark=true;
try {
session.save(obj);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
mark=false;
}
return mark;
}
public boolean update(T obj){
Session session = getSession() ;
boolean mark=true;
try {
session.saveOrUpdate(obj);
} catch (Exception e) {
// TODO Auto-generated catch block
mark=false;
e.printStackTrace();
}
return mark;
}
@SuppressWarnings("unchecked")
public T getObjectById(int id,Class<T> c){
Session session = getSession() ;
T obj=null;
try {
obj = (T) session.get(c, id);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj ;
}
public boolean delete(T obj){
Session session = getSession() ;
boolean mark=true;
try {
session.delete(obj);
} catch (Exception e) {
// TODO Auto-generated catch block
mark=false;
e.printStackTrace();
}
return mark;
}
/**
* 分页
*/
@SuppressWarnings("unchecked")
public List<T> Page(String hql,int pageIndex,int pageSize){
Session session = getSession() ;
List<T> lis=null;
try {
Query query=session.createQuery(hql);
query.setFirstResult((pageIndex-1)*pageSize);
query.setMaxResults(pageSize);
lis = query.list();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return lis;
}
}
在这个类中,封装了Hibernate的DAO中最常见的业务:查询、修改、添加、删除、分页等,但是在这个封装类中没有用到事务处理。
3.3 定义代理类相关的处理类
package cn.com.bochy.hander;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.hibernate.Session;
import org.hibernate.Transaction;
import cn.com.bochy.until.HibernateUtilImpl;
//与代理类相关的处理类
public class Hander implements InvocationHandler{
private HibernateUtilImpl<?> Util;//被代理类对象
public Hander(HibernateUtilImpl<?> o){
this.Util=o;//通过构造方法给被代理对象赋值
}
@Override
//Object proxy:代理对象
//Method method:被代理对象的主业务逻辑的方法
//Object[] args:上述方法的参数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Session session = Util.getSession();
Transaction tx=session.beginTransaction();
Object o1=null;
try {
o1=method.invoke(Util, args);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}
return o1;
}
//得到代理对象
public Object getProxy(){
//ClassLoader loader:类加载器
//Class<?>[] interfaces:代理类的实现接口
//InvocationHandler h:与代理对象相关的处理对象
//生成一个被代理对象object的代理对象
return Proxy.newProxyInstance(Util.getClass().getClassLoader(),
Util.getClass().getInterfaces(), this);
}
}
在这个处理类中,统一对Hibernate的DAO中最常见的业务的进行了事务处理。
3.4 测试
package cn.com.bochy.test;
import cn.com.bochy.entity.Stu;
import cn.com.bochy.hander.Hander;
import cn.com.bochy.iuntil.IHibernate;
import cn.com.bochy.until.HibernateUtilImpl;
public class TestProxy {
public static void main(String[] args) {
Hander hander=new Hander(new HibernateUtilImpl<Stu>());
Object proxy=hander.getProxy();
@SuppressWarnings("unchecked")
IHibernate<Stu> s=(IHibernate<Stu>)proxy;
System.out.println(s.getList("from Stu").size());
Stu s1=new Stu();
s1.setName("chen2");
s.Save(s1);
}
}
如果学生s1已经存入数据库,则说明事务管理有效。