SSH笔记-Hibernate对象的状态转换

1、对象状态转换跟session的操作函数有关

2、对象状态有三种:临时对象,持久化对象,游离对象

3、对象:
(1). 临时对象: session中不存在,数据库中不存在,通过new创建的对象的状态
(2). 持久化对象:session中存在,数据库中存在,调用session的save()、update()、saveOrUpdate()等方法时的对象的状态
(3). 游离对象: session中不存在,数据库中存在,session关闭后的对象状态

4、三种状态的区别
①临时对象:session中不存在,数据库中不存在
②持久化对象:session中存在,数据库中存在
③游离对象:session中不存在,数据库中存在


5、对象转换示意图
对象转换

6、对象转换时,session调用的函数:
①只要遇到用new来创建的的对象,都是临时对象
②要变成持久化对象,通常都会调用session的get()、load()、update()、saveOrUpdate()、save()函数
③持久化对象在回收之前,需要先用close()或者clean()或者evict()变成游离对象,然后用delete()变成删除状态等待回收
④临时对象只能变成持久化对象或者等待回收
⑤持久化对象只能变成游离对象或者直接变成删除状态
⑥游离对象只能变成持久化对象或者变成删除状态或者直接被回收

7、没什么好说的,就记住什么情况对象状态会变成什么就好了

8、hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>

        <!-- 配置连接数据库基本信息 -->
        <property name="connection.username">root</property>
        <property name="connection.password"></property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost/hebernateTEST</property>

        <!-- 配置hibernate基本信息 -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- 执行操作室是否在控制台打印sql -->
        <property name="show_sql">true</property>
        <!-- 是否对sql格式化 -->
        <property name="format_sql">true</property>

        <!-- 指定自动生成数据表的策略 -->
        <property name="hbm2ddl.auto">update</property>

        <!-- 设置 Hibernate 的事务隔离级别 -->
        <property name="connection.isolation">2</property>

        <!-- 设置调用delete()时,OID变成null -->
        <property name="hibernate.use_identifier_rollback">true</property>

        <!-- 指定关联的 *.hbm.xml文件(目录结构) 每个.hbm.xml对应一个数据表-->
        <mapping resource="com/demo/sshtest/Info.hbm.xml"/>

    </session-factory>
</hibernate-configuration>

9、Info.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-4 16:22:30 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.demo.sshtest.Info" table="INFO">
        <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="pswd" type="java.lang.String">
            <column name="PSWD" />
        </property>
        <property name="description" type="java.lang.String">
            <column name="DESCRIPTION" />
        </property>
    </class>
</hibernate-mapping>

10、Info.java

package com.demo.sshtest;

public class Info {

    public Integer id;
    public String name;
    public String pswd;
    public String description;
    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 String getPswd() {
        return pswd;
    }
    public void setPswd(String pswd) {
        this.pswd = pswd;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    public Info(){}
    public Info(String name, String pswd, String description) {
        super();
        this.name = name;
        this.pswd = pswd;
        this.description = description;
    }
    public Info(Integer id,String name, String pswd, String description) {
        super();
        this.id = id;
        this.name = name;
        this.pswd = pswd;
        this.description = description;
    }
    @Override
    public String toString() {
        return "Info [id=" + id + ", name=" + name + ", pswd=" + pswd + ", description=" + description + "]";
    }

}

11、TestSession.java

package com.demo.sshtest;


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
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 TestSession {

    public SessionFactory sessionFactory;
    public Session session;
    public Transaction transaction;

    //对象的状态(临时对象,持久化对象,游离对象)
    //1、临时对象:   session中不存在,数据库中不存在,通过new创建的对象的状态
    //2、持久化对象:session中存在,数据库中存在,调用session的save()、update()、saveOrUpdate()等方法时的对象的状态
    //3、游离对象:   session中不存在,数据库中存在,session关闭后的对象状态

    //            session    database
    //临时对象      F           F
    //持久化对象     T           T
    //游离对象      F           T


    //这里用@xxxx的junit调试的时候 要把hamcrest-all-1.3.jar、junit.jar加载上
    @Before
    public  void init(){
        Configuration configuration = new Configuration().configure();
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
        System.out.println("init");
    }
    @After
    public  void destory(){
        transaction.commit();
        session.close();
        sessionFactory.close();
        System.out.println("destory");
    }

    @Test
    public void Refresh(){
        //执行refresh()时,会执行select语句,查询数据库,更新session
        Info info = (Info)session.get(Info.class, 1);
        info.setName("sdfadfadsfa");
        System.out.println("========"+info);
        session.refresh(info);
        System.out.println("========"+info);
    }
    @Test
    public void Flush(){
        //Flush 类似Update 操作
        //作用: 使数据表中的记录和 Session 缓存中的对象的状态保持一致. 为了保持一致, 则可能会发送对应的 SQL 语句
        //1. 在 Transaction 的 commit() 方法中: 先调用 session 的 flush 方法, 再提交事务
        //2. flush() 方法会可能会发送 SQL 语句, 但不会提交事务. 
        //3. 注意: 
        //      1)在未提交事务或显式的调用 session.flush() 方法之前, 也有可能会进行 flush() 操作.
        //      2)执行 HQL 或 QBC 查询, 会先进行 flush() 操作, 以得到数据表的最新的记录
        System.out.println("testflush");
        Info info = (Info)session.get(Info.class, 1);
        info.setPswd("323");
        session.flush();
        //flush后没更新数据库,但是destory()的时候执行了commit()操作,这个时候数据库才更新了pswd
    }
    @Test
    public void Clear(){
        //没执行clear(),session里面的EntityName是有数据的,且info2执行session.get()的时候不会执行select语句
        //执行clear()之后session里面是被清空的,而且info2执行session.get()的时候会再次执行select语句
        Info info = (Info)session.get(Info.class, 1);
        System.out.println("========"+info);
        System.out.println("========"+session);
        session.clear();
        System.out.println("========"+session);
        Info info2 = (Info)session.get(Info.class, 1);
        System.out.println("========"+info2);
    }
    @Test
    public void Save(){
        //1、使一个临时对象变为持久化对象
        //2、为对象分配OID(即:id)
        //3、在flush缓存时,会执行insert语句(在transaction.commit()方法中)
        //4、设置主键id的话,需要在save()方法之前才有效
        //5、持久化对象的OID(即:id)是不能被修改的
        //6、若记录的OID(即:id)是由底层数据库使用自增的方式生成的, 则在调用 save() 方法时, 就会立即发送 INSERT 语句
        System.out.println("Save");
        Info info = new Info("name1", "pswd1", "desc1");
        session.save(info);
    }
    @Test
    public void Persist(){
        //1、类似save()方法,也会执行insert语句
        //2、调用persist()方法之前,如果对象有OID(即:id),则不执行insert并且抛出异常(save()方法不会)
        System.out.println("Persist");
        Info info = new Info("name1", "pswd1", "desc1");
        session.persist(info);
    }
    @Test
    public void Get(){
        //1、获取指定id的数据
        //2、调用get()方法马上执行查询(立即检索)
        //3、session没关闭,需要使用对象时,如果数据表中没有对应记录,返回null
        //4、在需要初始化代理对象前,关闭了session,不影响,因为已经加载代理对象了
        System.out.println("Get");
        Info info = (Info)session.get(Info.class, 1);
        System.out.println(info);
    }
    @Test
    public void Load(){
        //1、获取指定id的数据
        //2、调用load()方法时,如果不使用对象,则不会立即执行查询操作,并且返回一个代理对象 (延迟加载/延迟检索)
        //3、session没关闭,需要使用对象时,如果数据表中没有对应记录,抛出异常(因为已经返回代理对象了,但是对象不存在,所以异常)
        //4、load()方法可能抛出懒加载异常LazyInitializationException:在需要初始化代理对象前,关闭了session,就会抛这个异常
        System.out.println("Load");
        Info info = (Info)session.load(Info.class, 1);
        System.out.println(info.getClass().getName());
        //System.out.println(info);
    }
    @Test
    public void Update(){
        //1、若更新一个持久化对象,不需要显式调用update(),因为在调用transaction.commit()方法时,commit()方法会先执行session.flush()
        //2、更新一个游离对象,需要显式调用session.update(),把游离对象转换成持久化对象
        //3、注意事项:
        //  1)要更新的有你对象和数据表记录,不管是否相同,都会执行update语句
        //  2)如果希望update()方法只有在session数据有改变的情况下才执行,则需要到*.hbm.xml的class标签里面,加上select-before="true"
        //  3)select-before默认为false,一般情况下不设置这个参数
        //  4)如果数据表中没有对应id的记录,还使用update()的话,会抛出异常
        //  5)如果update()方法关联的是一个游离对象时,session缓存中存在相同id的持久化对象,则会抛出异常,因为session缓存中不能存在OID相同的两个对象
        System.out.println("Update");
        Info info = (Info)session.get(Info.class, 1);
        //info.setName("aoaoaoao");
        session.update(info);
    }
    @Test
    public void saveOrUpdate(){
        //1、如果OID不为null,但数据表中没有和请求对应的记录,saveOrUpdate()方法就会抛出 异常(如:下面info.setId是2,但是数据库里面没有id为2的记录,这个时候会抛出异常)
        //2、OID值等于id的unsaved-value属性值的对象,也会被认为是个游离对象
        //  (1)unsaved-value的值与子类对象的Id相等,表明没有持久化,调用save()
        //  (2)unsaved-value的值与子类对象的Id不相等,表明已持久化,调用Update()
        //  (3)unsaved-value默认值是null
        System.out.println("saveOrUpdate");
        Info info = new Info("dddsd", "bfsdfsbb", "xxsdfsdx");
        info.setId(2);
        session.saveOrUpdate(info);
    }
    @Test
    public void merge(){
        //就是用来把其他状态的对象变成持久化对象
        //1、判断是游离对象还是临时对象
        //2、如果是游离对象,先检查session里面是否存在OID,存在就执行update,不存在就加载数据库中对应id的持久化对象,然后执行update,最后不管是否存在OID,都会返回持久化对象
        //3、如果是临时对象,创建一个新的对象,然后把下面info对象复制过去,再持久化新的对象,然后执行insert
        System.out.println("merge");
        Info info = (Info)session.get(Info.class, 1);
        session.clear();
        session.merge(info);

    }
    @Test
    public void delete(){
        //1、可以删除一个持久化对象,也可以删除一个游离对象
        //2、逻辑运行顺序:(1)执行delte语句(2)从session删除这个对象
        //3、cfg.xml配置文件中的hibernate.use_identifier_rollback默认为false,如果改为true,delete()会把对象OID改为null,把对象变成临时对象
        //4、执行条件:OID和表中记录有对应,就能执行delete(),否则没反应
        //5、如果OID在表中没有记录,则抛出异常
        System.out.println("delete");
        //删除游离对象
        //Info info = new Info();
        //info.setId(1);
        //session.delete(info2);
        //删除持久化对象
        Info info2 = (Info)session.get(Info.class, 7);
        session.delete(info2);
        System.out.println(info2);
    }
    @Test
    public void evict(){
        //1、从session缓存中把指定持久化对象移除
        System.out.println("evict");
        Info info1 = (Info)session.get(Info.class, 5);
        Info info2 = (Info)session.get(Info.class, 6);
        info1.setName("asdfasdfa");
        info2.setName("fefeefedfdfdfef");
        //info1的数据不会更新到数据库
        //info2的数据会更新到数据库
        session.evict(info1);
    }
    @Test
    public void Dowork(){
        //通过调用doWork()方法,就能调用jre中原生的jdbc接口
        System.out.println("dowork");
        session.doWork(new Work() {
            @Override
            public void execute(Connection con) throws SQLException {
                String sql = "select * from info where id=6";
                Statement stmt = null;  
                ResultSet rs = null;  
                PreparedStatement pstmt;
                try{  
                    stmt = con.createStatement();
                    //传入类似sql="select * from test"  
                    pstmt=con.prepareStatement(sql);   
                    rs=pstmt.executeQuery();  
                    while (rs.next()) {  
                        System.out.println("打印resultset里面的参数值:");
                        System.out.println("id:"+rs.getInt("id"));
                        System.out.println("name:"+rs.getString("name"));
                        System.out.println("pswd:"+rs.getString("pswd"));
                        System.out.println("description:"+rs.getString("description"));
                    }  
                    rs.close();  
                }catch (Exception e){  
                    System.out.println("数据查询失败!");  
                    e.printStackTrace();  
                }
                try{  
                    if(rs!=null)  
                           rs.close();  
                    if(stmt!=null)  
                           stmt.close();  
                }catch(Exception e) {  
                    e.printStackTrace();  
                }
            }
        });
    }
}

session每个方法函数的调用方法里面,都写满了注释,有关的作用、解释、注意事项都有了,调试的时候,是用junit的,直接选了要运行的方法函数然后用junit运行就好了

12、项目目录
项目目录

13、运行结果:没什么好截图的,运行以下,看看select语句运行之后,对应不同参数,update语句或者insert语句select语句等,有没有按照函数应发挥的作用在运行,就好了。

14、demo
https://download.csdn.net/download/qq_22778717/10338899

猜你喜欢

转载自blog.csdn.net/qq_22778717/article/details/79881956