发现问题
- 如果集合Hibernate来编写DAO类,那么会遇到这样一个问题,那就是:Hibernate的Session操作对象需要在哪里实例化完成?
- 如果由Service层(也许是业务层)调用DAO方法的时候传入Session对象,这就需要业务层于Hibernate紧密耦合,但不希望业务层在调用方法的时候,知道底层是如何实现的,所以不应该由业务层实例化Session对象
public boolean save(Session session, Department department){
return session.save(department)!=null;
}
使用当前线程管理Session对象
使用本地线程管理session的具体实现
- 将获取Session对象的操作包装为一个工具类,因为这个工具类于Hibernate有关,所以将这个类放在"util.hibernate"包下
package mao.shu.util.hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
/**
* 单例设计模式
*/
public class HibernateUtil {
private SessionFactory sessionFactory;
private static HibernateUtil instance = new HibernateUtil();
/**
* 私有化构造器
*/
private HibernateUtil(){}
public static HibernateUtil getInstance(){
return instance;
}
publicSessionFactory getSessionFactory(){
if(this.sessionFactory == null){
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties()).buildServiceRegistry();
this.sessionFactory = configuration.buildSessionFactory(serviceRegistry);
}
return this.sessionFactory;
}
public Session getSession(){
return this.getSessionFactory().getCurrentSession();
}
}
- 修改hibernate.cfg.xml文件
- 如果整个其他框架会有更简单的方法,不需要配置此配置项
<!--开启管理当前session对象-->
<property name="hibernate.current_session_context_class">thread</property>
- 修改DAO方法
public boolean save(Department department){
Session session = HibernateUtil.getInstance().getSession();
return session.save(department)!=null;
}
- 编写测试方法
@Test
public void save() {
//测试获取的session是否为同一个对象
System.out.println(HibernateUtil.getInstance().getSession().hashCode());
System.out.println(HibernateUtil.getInstance().getSession().hashCode());
System.out.println(HibernateUtil.getInstance().getSession().hashCode());
Session session = HibernateUtil.getInstance().getSession();
Transaction transaction = session.beginTransaction();
DepartmentDAO departmentDAO = new DepartmentDAO();
for (int i = 0; i < 10; i++) {
Department dept = new Department();
dept.setName("session测试"+i);
departmentDAO.save(dept);
}
transaction.commit();
System.out.println(session.isOpen());
}
-
从测试结果中可以看出,每个session都是同一线程的session
-
若 Session 是由 thread 来管理的, 则在提交或回滚事务时, 已经关闭 Session 了.
Session生命周期于本地线程绑定
批量处理数据
-
如果要批量处理数据最快的速度还是使用原生sql的API,因为如果使用Hibernate提供的方式最后也是要转换为sql语句进行执行.
-
使用原生sql语句进行批处理操作(推荐使用)
@Test
public void testBathSql(){
long beginTime = System.currentTimeMillis();
Session session = HibernateUtil.getInstance().getSession();
Transaction transaction = session.beginTransaction();
session.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
String sql = "INSERT INTO GG_DEPARTMENT(ID,NAME)VALUES(?,?)";
PreparedStatement pstm = connection.prepareStatement(sql);
for (int i = 0; i < 10000; i++) {
pstm.setInt(1,i);
pstm.setString(2,"sql批处理测试"+i);
pstm.addBatch();
}
System.out.println(pstm.executeBatch().length);
}
});
transaction.commit();
long endTime = System.currentTimeMillis();
System.out.println("共花费:"+(float)(endTime - beginTime)/1000 + "s");
}
- 执行结果
- 通过 Session 来进行批量操作(不推荐)
@Test
public void testBath(){
long beginTime = System.currentTimeMillis();
Session session = HibernateUtil.getInstance().getSession();
Transaction transaction = session.beginTransaction();
for (int i = 0; i < 10000; i++) {
Department dept = new Department();
dept.setName("批处理测试"+i);
session.save(dept);
if ((i+1)%20==0){
session.flush();//同步数据
session.clear();//清理缓存
}
}
transaction.commit();
long endTime = System.currentTimeMillis();
System.out.println("共花费:"+(float)(endTime - beginTime)/1000 + "s");
}
- 数据库中保存的数据不完整,
-
使用HQL进行批处理(不推荐)
-
通过StatelessSession来进行批量操作(不推荐)