SSH笔记-Hibernate的管理Session和批量操作数据库

1、相关文件
(1)session管理相关的文件:TestInfo.java、SessionUtil.java、TestDao.java、TestSessionManagement.java、TestInfo.hbm.xml、hibernate.cfg.xml(配置session管理方式)
(2)批量操作数据库相关的文件:TestInfo.java、TestInfo.hb.xml、TestBatch.java

2、hibernate管理session对象方法:
(1)Session 对象的生命周期与本地线程绑定
(2)Session 对象的生命周期与 JTA 事务绑定
(3)Hibernate 委托程序管理 Session 对象的生命周期

3、对应上一点,hibernate.cfg.xml的hibernate.current_session_context_class 属性配置方法:
①thread:Session 对象的生命周期与本地线程绑定
②jta*: Session 对象的生命周期与 JTA 事务绑定
③managed:Hibernate 委托程序来管理 Session 对象的生命周期

4、Session 对象的生命周期与本地线程绑定时,逻辑顺序:
(1)线程调用SessionFactory对象的getCurrentSession()方法,该方法创建一个Session对象,并把Session对象与线程绑定,然后把Session对象返回给线程
(2)线程调用上一点中返回点Session对象(无论多少次调用,只要session不关闭,调用的始终都是同一个sessino对象)
(3)线程提交Session对象关联事务,hibernate会自动刷新Session对象缓存和提交事务,然后自动关闭Session对象。线程撤销Session对象关联事务,hebernate会自动关闭Session对象
(4)这个时候,线程再次调用SessionFactory对象的getCurrentSession()方法时,会重新分配一个新的Session对象与线程绑定,且返回给线程

5、管理Session的使用场景:一个线程需要多次调用同一个session进行操作的时候

6、注意事项:如果多个方法调用同一个事务的时候,可以写个Dao类进行中转

7、批量操作注意事项:
①如果采用identity生成规则生成主键,hibernate无法在jdbc进行批量插入
②批量操作时,建议关闭二级缓存
③HQL无法做批量插入操作

8、批量操作方式:
①通过 Session (最简单,配置好配置文件后直接用set方法和save()等方法就可以)
②通过 HQL (功能多,可以根据需要设置操作的语句)
③通过 StatelessSession (跟Session差不多,不过没有缓存,不会跟二级缓存有交互)
④通过 JDBC API (效率最高)

9、通过 Session批量操作:
(1)如果通过一个 Session 对象来处理大量持久化对象, 应该及时从缓存中清空已经处理完毕并且不会再访问的对象
(2)具体的做法是在处理完一个对象或小批量对象后, 立即调用 flush() 方法刷新缓存, 然后在调用 clear() 方法清空缓存
(3)使用约束:
①需要在 Hibernate 配置文件中设置 JDBC 单次批量处理的数目, 应保证每次向数据库发送的批量的 SQL 语句数目与 batch_size 属性一致
②若对象采用 “identity” 标识符生成器, 则 Hibernate 无法在 JDBC 层进行批量插入操作
③进行批量操作时, 建议关闭 Hibernate 的二级缓存

10、通过HQL批量操作:
(1)HQL 不能进行批量插入操作,只支持更新删除查询操作

11、通过StatelessSession批量操作:
(1)StatelessSession没有缓存,通过StatelessSession来加载、保存或更新后的对象处于游离状态
(2)StatelessSession不会与Hibernate的第二级缓存交互
(3)当调用StatelessSession的save()、update()或delete()方法时,这些方法会立即执行相应的SQL语句
(4)StatelessSession不会进行脏检查,因此修改了对象属性后,还需要调用StatelessSession的update()方法来更新数据库中数据
(5)StatelessSession不会对关联的对象进行任何级联操作
(6)通过同一个StatelessSession对象两次加载OID为1的Customer对象,得到的两个对象内存地址不同
(7)StatelessSession所做的操作可以被Interceptor拦截器捕获到,但是会被Hibernate的事件处理系统忽略掉

12、TestInfo.java 数据模型

package com.demo.sshtest;

public class TestInfo {

    public Integer id;
    public String name;
    public int age;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

}

13、TestInfo.hbm.xml 数据模型的关系映射配置

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-4-23 22:41:28 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.demo.sshtest.TestInfo" table="TESTINFO">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        <property name="age" type="int">
            <column name="AGE" />
        </property>
    </class>
</hibernate-mapping>

14、SessionUtil.java 用于获取当前线程的session对象

package com.demo.sshtest;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

public class SessionUtil {

    //因为多个线程需要用到该获取session的方法,需要保证调用的类里面仅有一个session的实例,且保证这个session是该线程当前的session,所以这里用单例模式

    private SessionUtil(){}

    private static SessionUtil instance = new SessionUtil();

    public static SessionUtil getInstance(){
        return instance;
    }

    private SessionFactory sessionFactory;

    //初始化SessionFactory
    public SessionFactory getSessionFactory(){
        if(sessionFactory==null){
            Configuration configuration = new Configuration().configure();
            ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        }
        return sessionFactory;
    }

    //hibernate为SessionFactory提供了一个getCurrentSession方法,用于获取当前线程的session对象
    public Session getSession(){
        return getSessionFactory().getCurrentSession();
    }

}

15、TestDao.java 通过和当前线程(调用该类的save()方法的持久化类所在的线程)绑定session对象,从内部获取session对象

package com.demo.sshtest;

import org.hibernate.Session;

public class TestDao {

    public void save(TestInfo testInfo){
        //通过和当前线程绑定session对象,从内部获取session对象
        //好处:
        //1、是调用方法时,只需要传入持久化对象,不用传入其他参数,不用了解该方法函数的结构(不需要从外部传入session对象)
        //2、多个dao方法可以使用同一个事物
        Session session = SessionUtil.getInstance().getSession();
        session.save(testInfo);
    }

}

16、TestSessionManagement.java 测试session管理

package com.demo.sshtest;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestSessionManagement {

    private SessionFactory sessionFactory;
    private Session session;
    private Transaction transaction;

    @Test
    public void testSessionMa(){
        //获取session
        //开启事务
        Session session = SessionUtil.getInstance().getSession();
        System.out.println(session.hashCode());
        Transaction transaction = session.beginTransaction();
        TestDao testDao = new TestDao();
        TestInfo testInfo = new TestInfo();
        testInfo.setName("fafadsad");
        testInfo.setAge(12);
        testDao.save(testInfo);
        //提交事务
        //如果session是有thread管理的,这提交或回归后会被关闭
        transaction.commit();
        System.out.println(session.isOpen());
    }
}

在SessionUtil.getInstance().getSession()中获取了当前线程的session对象后,就能通过set方法修改对象属性,然后提交事务即可,因为配置了session管理方式为thread(线程式管理),提交之后hibernate会自动关闭session,所以不需要做session和transaction的close()的操作

17、TestBatch.java 测试批量操作

package com.demo.sshtest;

import java.sql.Connection;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.jdbc.Work;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestBatch {

    //批量操作
    //注意事项:
    //1、如果采用identity生成规则生成主键,hibernate无法在jdbc进行批量插入
    //2、批量操作时,建议关闭二级缓存
    //3、HQL无法做批量插入操作

    private SessionFactory sessionFactory;
    private Session session;
    private StatelessSession statelessSession;
    private Transaction transaction;

    @Before
    public void init(){
        Configuration configuration = new Configuration().configure();
        ServiceRegistry serviceRegistry = 
                new ServiceRegistryBuilder().applySettings(configuration.getProperties())
                                            .buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);

        session = sessionFactory.openSession();
        statelessSession= sessionFactory.openStatelessSession();
        transaction = session.beginTransaction();
    }

    @After
    public void destroy(){
        transaction.commit();
        session.close();
        statelessSession.close();
        sessionFactory.close();
    }
    @Test
    public void insertOriData(){
        //插入测试数据
        for(int number=1;number<20;number++){
            TestInfo testInfo = new TestInfo();
            testInfo.setName("name_"+number);
            testInfo.setAge(number);
            session.save(testInfo);
        }
    }
    @Test
    public void TestBatch1(){
        //通过JDBC api 批量操作
        session.doWork(new Work() {

            @Override
            public void execute(Connection arg0) throws SQLException {
                //通过JDBC API 操作,效率最高
            }
        });
    }
    @Test
    public void TestBatch2(){
        //通过session进行批量操作
        TestInfo testInfo = null;
        for(int i=0;i<6;i++){
            testInfo = new TestInfo();
            testInfo.setName("aaaaaaaa"+i);
            testInfo.setAge(i);
            session.save(testInfo);
        }
    }
    @Test
    public void testBatch3(){
        //通过statelesssession进行批量操作
        //1、StatelessSession没有缓存,通过StatelessSession来加载、保存或更新后的对象处于游离状态
        //2、StatelessSession不会与Hibernate的第二级缓存交互
        //3、当调用StatelessSession的save()、update()或delete()方法时,这些方法会立即执行相应的SQL语句,而不会仅计划执行一条SQL语句
        //4、StatelessSession不会进行脏检查,因此修改了Customer对象属性后,还需要调用StatelessSession的update()方法来更新数据库中数据
        //5、StatelessSession不会对关联的对象进行任何级联操作
        //6、通过同一个StatelessSession对象两次加载OID为1的Customer对象,得到的两个对象内存地址不同
        //7、为了解决内存占用过大问题,使用可滚动的结果集 org.hibernate.ScrollableResults, 该对象中实际上并不包含任何对象, 只包含用于在线定位记录的游标. 只有当程序遍历访问 ScrollableResults 对象的特定元素时, 它才会到数据库中加载相应的对象
        ScrollableResults rs = statelessSession.createQuery("FROM TestInfo").scroll(ScrollMode.FORWARD_ONLY);
            while ( rs.next() ) {
                TestInfo testInfo = (TestInfo) rs.get(0);
                System.out.println(testInfo.getId()+"-"+testInfo.getName()+"-"+testInfo.getAge());
                testInfo.setName(testInfo.getId()+"-name-"+testInfo.getAge());
                session.update(testInfo);
            }

    }
}

只是对应3种批量操作方法写了一下,没什么好说的

18、项目目录
项目目录

19、demo
https://download.csdn.net/download/qq_22778717/10372560

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值