• Hibernate学习(二)


    持久化对象的声明周期

    1、Hibernate管理的持久化对象(PO persistence object )的生命周期有四种状态,分别是transient、persistent、detached和removed,如图所示:

    • 瞬时状态:new出来的对象仅仅存在虚拟机的内存中,虚拟机关闭数据丢失
    • 持久化状态:通过save方法保存到数据库中,即使虚拟机关闭也可以中数据库中读取到想要的数据。通过get load find从数据库加载到数据并没有抛出异常,就立即进入持久化状态,并不是非要提交事务才进入持久化状态,执行完save操作就已经是持久化状态了
    • 游离态:把session关闭或者将对象驱除或者清除了就是游离的状态
    • 移除状态:通过delete方法之后,数据库中没有数据了,但数据加载到了jvm所管理内存中,对象对应的内存中是有数据的,类似于瞬时状态

    2、测试案例

    创建表sql

    --Mysql
    DROP TABLE IF EXISTS t_customer ;
    
    CREATE TABLE t_customer (
        id  INT(5) PRIMARY KEY ,
        email  VARCHAR(60)  UNIQUE NOT NULL,
        password VARCHAR(32) NOT NULL ,
        nickname VARCHAR(150) ,
        gender VARCHAR(3) ,
        birthdate DATE ,
        married     CHAR(1)
    );
    
    
    --Oracle
    CREATE TABLE t_customer (
        id  NUMBER(5) PRIMARY KEY ,
        email  VARCHAR2(60)  UNIQUE NOT NULL,
        password VARCHAR2(32) NOT NULL ,
        nickname VARCHAR2(150) ,
        gender VARCHAR2(3) ,
        birthdate DATE ,
        married     CHAR(1)
    );

    持久化对象类

    package ecut.session.entity;
    
    import java.util.Date;
    
    /**
     * 实体类 Customer <================> 数据库表: t_customer
     *            属性            <================>        列
     *        id                 <================>       id
     *        emial             <================>         email
     *        password     <================>         password
     *        nickname         <================>         nickname
     *        gender         <================>         gender
     *        birthdate     <================>         birthdate
     *        married         <================>         married
     *        
     *   new Customer();         <==========>    一条记录 (关系)
     *   
     */
    public class Customer {
    
        // 对象标识符 ( Object Identifier ) 属性 ( 对应数据库主键 ) 使用包装类型,才会有null值,才可以执行saveOrUpdate
        private Integer id; // 属性的值 被称作 对象标识符
        
        private String email;
        private String password;
        private String nickname;
        private char gender;
        private Date birthdate;
        private boolean married;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public String getNickname() {
            return nickname;
        }
    
        public void setNickname(String nickname) {
            this.nickname = nickname;
        }
    
        public char getGender() {
            return gender;
        }
    
        public void setGender(char gender) {
            this.gender = gender;
        }
    
        public Date getBirthdate() {
            return birthdate;
        }
    
        public void setBirthdate(Date birthdate) {
            this.birthdate = birthdate;
        }
    
        public boolean isMarried() {
            return married;
        }
    
        public void setMarried(boolean married) {
            this.married = married;
        }
    
    }

    映射文件

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    <hibernate-mapping>
    
        <class name="ecut.session.entity.Customer" table="t_customer">
        
            <!-- 对于 与 数据库主键 对应的 对象标识符属性 来说,要单独使用 id 标签来映射 -->
            <id name="id" type="integer" column="id" >
                <generator class="increment" /> <!-- 由 hibernate 提供的 对象标识符 生成策略 -->
            </id>
        
            <!-- 指定 那个属性 ( name 指定属性名 )  对应 那个列 ( column 属性指定 列名 ) -->
            <property name="email" type="string" column="email" />
            <!-- 使用 type 属性指定 映射类型 ( 既不是 Java 类型,也不是 数据库类型,而是 中间类型 ( 媒婆 ) ) -->
            <property name="password" type="string" column="password" />
            <property name="nickname" type="string" column="nickname" />
            <!-- Java 中的 char 类型在 hibernate 中对应的映射类型是 character -->
            <property name="gender" type="character" column="gender" />
            <property name="birthdate" type="date"  column="birthdate" />
            <!-- Java 中的 boolean  类型在 hibernate 中对应的映射类型可以是 true_false 、yes_no  -->
            <property name="married" type="yes_no" column="married" />
        
        </class>
        
    </hibernate-mapping>

    hibernate配置文件

    <?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="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
            <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF8</property>
            <property name="hibernate.connection.username">root</property>
            <property name="hibernate.connection.password">123456</property>
            
            <!-- 设置事务隔离级别 , 取值可以是 1、2、4、8  
            1—Read uncommitted isolation
             2—Read committed isolation
             4—Repeatable read isolation
             8—Serializable isolation-->
            <property name="hibernate.connection.isolation">1</property>
            <!-- 设置事务是否自动提交 , 取值可以是 true 、false -->
            <property name="hibernate.connection.autocommit">false</property>
            
            <!-- 指定数据方言类 -->
            <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
            
            <!-- 指示是否显示 执行过的 SQL 语句 -->
            <property name="hibernate.show_sql">true</property>
            <!-- 指示是否对 SQL 语句进行格式化输出 -->
            <property name="hibernate.format_sql">true</property>
            
            <mapping resource="ecut/session/entity/Customer.hbm.xml"/>
            
        </session-factory>
    
    </hibernate-configuration>

    配置文件中的核心配置说明

     java.sql.Connection 中定义的事务隔离级别:

    • public static final int    TRANSACTION_NONE    :    0
    • public static final int    TRANSACTION_READ_UNCOMMITTED    :    1
    • public static final int    TRANSACTION_READ_COMMITTED    :    2
    • public static final int    TRANSACTION_REPEATABLE_READ    :    4
    • public static final int    TRANSACTION_SERIALIZABLE    :    8

     测试类:

    package ecut.session.test;
    
    import java.util.Calendar;
    import java.util.Date;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    import ecut.session.entity.Customer;
    
    public class TestLifecycle {
        
        private SessionFactory factory ;
        private Session session ; 
        
        public @Before void init() {
            // 创建一个 Configuration 对象,用来读取配置文件 ( 默认位置、默认名称 )
            Configuration config = new Configuration();
            // 读取配置文件
            config.configure("ecut/session/hibernate.cfg.xml");
    
            //config.configure(); // 读取 默认位置 ( 当前 classpath ) 的 默认名称 ( hibernate.cfg.xml ) 的配置文件
    
            // 使用 Configuration 创建 SessionFactory
            factory = config.buildSessionFactory();
            
            // 创建 Session 对象 ( 这里的 Session 是 Java 程序 跟 数据库 之间的 会话 )
            session = factory.openSession();
        }
    
        public @Test void state() throws InterruptedException {
            
            Calendar calendar = Calendar.getInstance();
            
            Customer c = new Customer(); // Transient ( 瞬时状态 )
            
            c.setEmail( "zhangsanfeng@wudang.com" );
            c.setPassword( "hello2017" );
            
            calendar.set( 1345 , 5 , 10 );
            Date birthdate = calendar.getTime() ;
            c.setBirthdate( birthdate );
            c.setGender( '男' );
            
            c.setNickname( "张三丰" );
            c.setMarried( false );
            
            System.out.println( session.contains( c ) ); // false
            
            Transaction tran = session.beginTransaction(); // session.getTransaction().begin();
            session.save( c ); // Persistent ( 持久化状态 )
            System.out.println( "~~~1~~~~~~~~~~~~~~~~~~" );
            session.flush();  // 将当前尚未执行的 SQL 语句立即执行
            System.out.println( "~~~2~~~~~~~~~~~~~~~~~~" );
            Thread.sleep( 1 );
            System.out.println( "~~~3~~~~~~~~~~~~~~~~~~" );
            tran.commit(); // 提交事务 ( 如果还有没有执行的 SQL 语句就执行它们 )
            System.out.println( session.contains( c ) ); // true
            
            session.evict( c ); // Detached ( 游离状态 )
            
            System.out.println( session.contains( c ) ); // false,是否被session所管理,session中已经没有这个数据了
            
            System.out.println( c.getEmail() );//虚拟机中依然有数据
            
        }
        
        public @Test void removed() {
            
            Customer c = session.get( Customer.class ,  4 ); // 持久化状态
            
            if( c != null ) {
                
                System.out.println( session.contains( c ) );
                System.out.println( c.getEmail() );
                
                Transaction tran = session.getTransaction();
    
                tran.begin();
                session.delete(c); // 删除对象
                System.out.println( "~~~1~~~~~~~~~~~~~~~~~~" );
                session.flush(); // 将当前尚未执行的 SQL 语句立即执行
                System.out.println( "~~~2~~~~~~~~~~~~~~~~~~" );
                tran.commit();
                
                System.out.println( session.contains( c ) );
                System.out.println( c.getEmail() );
            }
        }
        
        public @After void destory(){
            session.close();
            factory.close();
        }
    
        
    
    }

    若没有flush操作则insert语句在提交事务之后输出执行,若有flush操作则将当前尚未执行的 SQL 语句立即执行即在提交事务之前输出insert语句。在save方法执行之后就已经是出于持久化状态无论sql语句是否执行。若处于游离态则对象已经不再被session所管理即contains方法返回false。

    测试类中的方法说明:

    • 判断指定的对象是否 被 Session 对象所管理:  boolean  contains( Object po )
    • 将尚未执行的SQL语句执行:        void     flush()
    • 将 一个 被 Session 管理的对象驱逐: void  evict( Object po )
    • 将 整个 Session 所管理的所有的对象全部清理: void  clear()
    • 如果 一个 Session 对象执行了 close() 方法,则该 Session 对象将无效,一次 曾经被它管理的对象也将进入游离状态

    3、四种状态的比较

    Persistent 和 Detached区别在于是否被session所管理
    核心: 处于 持久化状态的 对象 的 OID 与 数据库中的 某条记录的 主键 一定是 相等的。

    Hibernate中的核心类和接口

    1、org.hibernate.cfg.Configuration:Configuration类表示配置对象,用来读取并解析 hibernate 配置文件

    •     注意:Configuration类的configure实例方法负责读取配置文件(hibernate.cfg.xml)

    2、org.hibernate.SessionFactory:SessionFactory接口实例专门用来创建连接到指定数据库的会话对象
    3、org.hibernate.Session:Session接口的实例是hibernate应用的核心对象,提供了大量的对持久化对象进行操作的方法

    •     注意:这里的会话指的是当前的Java应用程序和数据库服务器之间的会话(绝对不是HttpSession)

    4、org.hibernate.Transaction:Transaction接口的实例表示事务对应的对象,用来对事务进行控制
    5、org.hibernate.query.Query:Query接口的实例是hibernate应用中查询时的核心对象

    • 注意:Hibernate早期(5.x之前)版本中使用query接口是org.hibernate.Query

    Session接口只要方法

    1、session接口中定义的用来操作持久化对象的方法

    • Serializable     save(Object object)     保存一个对象到数据库中并返回与之对应的对象标识符(主键的值)
    • void persist(Object object) 标准的JPA(Java Persistence API 应用程序编程接口(application program interface))提供的方法,用来持久化一个对象,javax.persistence.EntityManager中的方法
    • void saveOrUpdate(Object object) 用来更新一个持久化对象(需要根据对象标识符来实现),默认是根据对象标识符是否为null 来判断应该执行保存操作还是更新操作
    • void update(Object object) 用来持久化或更新一个对象
    • void delete(Object object) 用来删除一个持久化的对象
    • <T> T get(Class<T> entityType,Serializable id) 从数据库汇总查询一条记录并封装成一个相应类型的Java对象,默认不支持延迟加载,当id对应的数据不存在时返回null
    • <T> T load(Class<T> theClass,Serializable id)  从数据库汇总查询一条记录并封装成一个相应类型的Java对象,默认支持延迟加载,当id对应的数据不存在时抛出ObjectNotFoundException
    • <T> T find(Class<T> entityClass, Object primaryKey)  从数据库汇总查询一条记录并封装成一个相应类型的Java对象    javax.persistence.EntityManager中的方法,默认不支持延迟加载,当id对应的数据不存在时返回null
    • Query     createQuery(String queryString) 根据给定的 queryString 来创建一个查询器(基于HQL实现的)
    • void  evict(Object arg0) 将指定的对象从关联的session对象中驱逐

    2、保存操作的测试案例

    package ecut.session.test;
    
    import java.io.Serializable;
    import java.util.List;
    
    import org.hibernate.HibernateException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.query.Query;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import ecut.session.entity.Customer;
    
    public class TestSessionMethod {
        
        private SessionFactory factory ;
        private Session session ; 
        
        public @Before void init() {
            // 创建一个 Configuration 对象,用来读取配置文件 ( 默认位置、默认名称 )
            Configuration config = new Configuration();
            // 读取配置文件
            config.configure("ecut/session/hibernate.cfg.xml");
    
            //config.configure(); // 读取 默认位置 ( 当前 classpath ) 的 默认名称 ( hibernate.cfg.xml ) 的配置文件
    
            // 使用 Configuration 创建 SessionFactory
            factory = config.buildSessionFactory();
    
            // 创建 Session 对象 ( 这里的 Session 是 Java 程序 跟 数据库 之间的 会话 )
            session = factory.openSession();
        }
    
        public @Test void testSave() {
            
            Customer c = new Customer();
            
            c.setEmail( "zhangcuishan@wudang.com" );
            c.setPassword( "hello2017" );
            
            Transaction tran = session.getTransaction();
            
            try{
                tran.begin();
                // dynamic-insert="false" : 
                // insert   into  t_customer  (email, password, nickname, gender, birthdate, married, id)   values  (?, ?, ?, ?, ?, ?, ?)
                // dynamic-insert="true"
                // insert   into  t_customer  (email, password, gender , married ,id)   values  (?, ?, ?,?, ?)
                System.out.println( "customer.id : " + c.getId() );
                Serializable id = session.save( c );
                System.out.println( "id : " + id );
                System.out.println( "customer.id : " + c.getId() );
                tran.commit();
            } catch ( HibernateException e) {
                tran.rollback();
            }
            
        }
        
        public @Test void testPersist() {
            
            Customer c = new Customer();
            
            c.setEmail( "moshenggu@wudang.com" );
            c.setPassword( "hello2017" );
            
            Transaction tran = session.getTransaction();
            
            try{
                tran.begin();
                System.out.println( "customer.id : " + c.getId() );
                session.persist( c );
                System.out.println( "customer.id : " + c.getId() );
                tran.commit();
            } catch ( HibernateException e) {
                tran.rollback();
            }
            
        }
       public @After void destory(){
            session.close();
            factory.close();
        }
    
    }

    save方法是持久化对象之后并返回这个对象的主键,persist没有返回值,是标准JPA(Java Persistence API )提供的方法,来自  javax.persistence.EntityManager接口。另外执行插入操作时,不想对所有的字段执行insert操作可以在映射配置文件中的class标签中指定动态插入

    <class name="ecut.session.entity.Customer" table="t_customer" dynamic-insert="true" >

    3、删除测试案例

    package ecut.session.test;
    
    import java.io.Serializable;
    import java.util.List;
    
    import org.hibernate.HibernateException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.query.Query;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import ecut.session.entity.Customer;
    
    public class TestSessionMethod {
        
        private SessionFactory factory ;
        private Session session ; 
        
        public @Before void init() {
            // 创建一个 Configuration 对象,用来读取配置文件 ( 默认位置、默认名称 )
            Configuration config = new Configuration();
            // 读取配置文件
            config.configure("ecut/session/hibernate.cfg.xml");
    
            //config.configure(); // 读取 默认位置 ( 当前 classpath ) 的 默认名称 ( hibernate.cfg.xml ) 的配置文件
    
            // 使用 Configuration 创建 SessionFactory
            factory = config.buildSessionFactory();
    
            // 创建 Session 对象 ( 这里的 Session 是 Java 程序 跟 数据库 之间的 会话 )
            session = factory.openSession();
        }public @Test void testDelete1() {
            // 先尝试从数据库中获取某条记录对应的一个 Java 对象
            Customer c = session.get( Customer.class ,  3 );
            // 如果指定 id 对应的 对象存在 ( 数据库中有相应的记录 )
            if( c != null ) {
                
                Transaction tran = session.getTransaction();
                
                try{
                    tran.begin();
                    session.delete( c ); // 删除对象
                    tran.commit();
                    System.out.println(c.getId());
    
                } catch ( HibernateException e) {
                    tran.rollback();
                }
                
            }
        }
        
        public @Test void testDelete2() {
            
            // 自己创建一个对象并指定 id 
            Customer c = new Customer();
            c.setId(2); // 如果 id 是 2 的记录在数据库中存在
            
            Transaction tran = session.getTransaction();
    
            try {
                tran.begin();
                session.delete( c ); // 删除对象
                tran.commit();
            } catch (HibernateException e) {
                tran.rollback();
            }
    
        }
       public @After void destory(){
            session.close();
            factory.close();
        }
    
    }

    两种删除,第一种先查询,如果存在这个对象就执行删除操作,第二种直接根据id删除。

    4、查询测试案例

    package ecut.session.test;
    
    import org.hibernate.ObjectNotFoundException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import ecut.session.entity.Customer;
    
    public class TestLoadData {
        
        private SessionFactory factory ;
        private Session session ; 
        
        public @Before void init() {
            // 创建一个 Configuration 对象,用来读取配置文件 ( 默认位置、默认名称 )
            Configuration config = new Configuration();
            // 读取配置文件
            config.configure("ecut/session/hibernate.cfg.xml");
    
            //config.configure(); // 读取 默认位置 ( 当前 classpath ) 的 默认名称 ( hibernate.cfg.xml ) 的配置文件
    
            // 使用 Configuration 创建 SessionFactory
            factory = config.buildSessionFactory();
    
            // 创建 Session 对象 ( 这里的 Session 是 Java 程序 跟 数据库 之间的 会话 )
            session = factory.openSession();
        }
    
        public @Test void testGet1() {
            Customer c = session.get( Customer.class ,  2 );
            if( c != null ){
                System.out.println( c.getEmail() );
            } else {
                System.out.println( "数据库中没有对应的数据" );
            }
        }
        
        public @Test void testGet2() {
            System.out.println( "准备查询数据库" );
            Customer c = session.get( Customer.class ,  1 ); // 立即查询并返回数据
            if( c != null ){
                System.out.println( "获取到的数据是" );
                System.out.println( c.getEmail() );
            }
        }
    
        
        public @Test void testLoad1() {
            Customer c = null ;
            try{
                c = session.load( Customer.class ,  2 );
                System.out.println( c.getEmail() );
            } catch ( ObjectNotFoundException e) {
                System.out.println( "数据库中没有对应的数据 , " + e.getMessage() );
            }
        }
        
        /**  延迟加载 ( 懒加载 )  
         *        关闭对 Customer 的延迟加载: <class name="ecut.session.entity.Customer" table="t_customer"  lazy="false" >
         *        启用对 Customer 的延迟加载: <class name="ecut.session.entity.Customer" table="t_customer"  lazy="true" >
         * */
        public @Test void testLoad2() {
            System.out.println( "准备查询数据库" );
            Customer c = session.load( Customer.class , 1 ); // 默认并不立即查询,如果不存在会在最后面才抛出异常
            System.out.println( "获取到的数据是 Id" );
            System.out.println( c.getId() );  // 因为 id 是 load 方法中指定的,因此不需要查询数据库
            System.out.println( "获取到的数据是 Email" );
            System.out.println( c.getEmail() ); // 获取 id 之外的 其它 数据时,不得不查询数据库
        }
        
        public @Test void testFind1() {
            Customer c = session.find( Customer.class ,  2 );
            if( c != null ){
                System.out.println( c.getEmail() );
            } else {
                System.out.println( "数据库中没有对应的数据" );
            }
        }
        
        public @Test void testFind2() {
            System.out.println( "准备查询数据库" );
            Customer c = session.find( Customer.class ,  1); // 立即查询并返回数据
            if( c != null ){
                System.out.println( "获取到的数据是 " );
                System.out.println( c.getEmail() );
            }
        }
        
        public @After void destory(){
            session.close();
            factory.close();
        }
    
    }

    get 、load 、find三种查询方法的比较:

    • get 、load 、find 都是用来从数据库中加载一条记录并包装成指定类型的对象
    • get( Class<?> c , Serializable id )

        a、当 id 对应的数据在 数据库中不存在时,get 返回 null

        b、get 方法会立即查询数据库 并返回数据

    • load( Class<?> c , Serializable id )

        a、当 id 对应的数据在 数据库中不存在时,load 方法会抛出 ObjectNotFoundException
        b、load 方法 "默认" 不会立即查询数据库,而是等到要使用除了id之外的其它数据时才执行查询操作并返回数据
        关闭对 Customer 的延迟加载:

    <class name="ecut.session.entity.Customer" table="t_customer"  lazy="false" >

        启用对 Customer 的延迟加载:

    <class name="ecut.session.entity.Customer" table="t_customer"  lazy="true" >
    • find( Class<?> c , Serializable id ) 属于 JPA 规范中定义的方法 ( javax.persistence.EntityManager )

              a、当 id 对应的数据在 数据库中不存在时,find 返回 null
              b、find 方法会立即查询数据库 并返回数据

    5、查询多条数据测试案例

    package ecut.session.test;
    
    import java.io.Serializable;
    import java.util.List;
    
    import org.hibernate.HibernateException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.query.Query;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import ecut.session.entity.Customer;
    
    public class TestSessionMethod {
        
        private SessionFactory factory ;
        private Session session ; 
        
        public @Before void init() {
            // 创建一个 Configuration 对象,用来读取配置文件 ( 默认位置、默认名称 )
            Configuration config = new Configuration();
            // 读取配置文件
            config.configure("ecut/session/hibernate.cfg.xml");
    
            //config.configure(); // 读取 默认位置 ( 当前 classpath ) 的 默认名称 ( hibernate.cfg.xml ) 的配置文件
    
            // 使用 Configuration 创建 SessionFactory
            factory = config.buildSessionFactory();
    
            // 创建 Session 对象 ( 这里的 Session 是 Java 程序 跟 数据库 之间的 会话 )
            session = factory.openSession();
        }
    public @Test void query() {
            
            // Hibernate 3.x : org.hibernate.Query
            
            // HQL : Hibernate Query Language FROM之后跟的是实体类的类名 SELECT c FROM Customer AS c
            String HQL = "FROM Customer AS c ORDER BY c.id DESC" ; // SQL : SELECT * FROM t_customer 
            
            // 创建 查询器 
            //Query<?> query = session.createQuery( HQL);
            Query<Customer> query = session.createQuery( HQL , Customer.class );
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
            // 使用 查询器 进行查询
            List<Customer> list = query.list(); 
            
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
    
            for( Customer c : list ){
                System.out.println( c.getId() + " , " + c.getEmail() );
            }
    
        }
        
        public @After void destory(){
            session.close();
            factory.close();
        }
    
    }

    HQL : Hibernate Query Language FROM之后跟的是实体类的类名 SELECT c FROM Customer AS c,调用list方法可以指明具体的返回类型也可以用?代替。

    6、更新测试案例

    package ecut.session.test;
    
    import java.util.Date;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import ecut.session.entity.Customer;
    
    public class TestUpdate {
        
        private SessionFactory factory ;
        
        public @Before void init() {
            // 创建一个 Configuration 对象,用来读取配置文件 ( 默认位置、默认名称 )
            Configuration config = new Configuration();
            // 读取配置文件
            config.configure("ecut/session/hibernate.cfg.xml");
    
            //config.configure(); // 读取 默认位置 ( 当前 classpath ) 的 默认名称 ( hibernate.cfg.xml ) 的配置文件
    
            // 使用 Configuration 创建 SessionFactory
            factory = config.buildSessionFactory();
        }
    
        /** 更新一个持久化状态的对象中的数据 后 同步到数据库中 ,但是不用 update 方法 */
        public @Test void testUpdate1() throws InterruptedException {
            
            Session session = factory.openSession();
            
            // 执行查询操作获取数据
            Customer c = session.find( Customer.class ,  1 ); // 持久化状态
            
            if(c != null){
                System.out.println(  c.getNickname() +  " : " + c.getEmail() );
                
                Transaction tran = session.beginTransaction(); // 开启一个事务并返回该事务的引用
                
                //c.setEmail( "sanfeng@wudang.com" );
                //可以在映射配置文件中设置动态插入和动态更新,只更新所更改的数值
                c.setNickname( "三丰".equals( c.getNickname() ) ? "君宝" : "三丰" );//如果数据值更改了(只有数据更改了才会执行update语句),提交事务的时候更改的值会同步到数据库
                
                Thread.sleep( 1 );
                
                tran.commit(); // 提交事务
            }
            
            session.close();
            
        }
        
        /** 使用 update 方法将 游离状态 的对象 还原到 持久化状态*/
        public @Test void testUpdate2() {
            
            Session firstSession = factory.openSession();
            
            Customer c = firstSession.find( Customer.class ,  1 ); // 持久化状态
            
            firstSession.close(); // 游离状态
            
            String nickname = c.getNickname() ;
            //可以在映射配置文件中设置动态插入和动态更新,只更新所更改的数值
            c.setNickname( "三丰".equals( nickname ) ? "君宝" : "三丰" );
            
            Session secondSession = factory.openSession() ;
            
            secondSession.getTransaction().begin();
            secondSession.update( c ); // 将一个 游离状态 的对象重新转换到 持久化状态,无法动态更新,动态更新是针对持久化对象的,只有是持久化对象才知道数据是什么样的。
            secondSession.getTransaction().commit(); // 提交事务后,事务即结束
            
            System.out.println( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
            
            secondSession.getTransaction().begin();
            String email = c.getEmail() ;
            //已经是持久化对象因此可以动态对象
            c.setEmail( "sanfeng@wudang.com".equals( email ) ? "junbao@qq.com" :"zsf@qq.com" );
            secondSession.getTransaction().commit();
        }
        
        /** 使用 merge 方法 将一个 游离状态的 对象的 数据 合并到 与其id相等的持久化状态的对象中去*/
        public @Test void testUpdate3() {
            
            Session session = factory.openSession();
            
            Customer c1 = session.find( Customer.class ,  1 ); // c1 处于持久化状态
            
            session.evict( c1 ); // c1 开始进入到 游离状态
            
            String nickname = c1.getNickname() ;
            c1.setNickname( "三丰".equals( nickname ) ? "君宝" : "三丰" );
            
            Customer c2 = session.find( Customer.class ,  1 ) ; // 持久化状态
            
            
            // 根据 c1.id 来在 session 管理的对象中寻找 与它id 相同的对象
            // 如果找到 id 相同的对象,就将 c1 中的数据 合并到 相应的持久化状态的对象中去
            // 最后 merge 方法返回 那个持久化状态的对象
            Object o = session.merge( c1 ); // c1.id == c2.id id是一样的将两个对象的数据进行合并
            session.getTransaction().begin();
            session.getTransaction().commit();//只要事务开启之后提交就好了,代码位置没有要求
            
            System.out.println( o == c1 ); // false
            System.out.println( o == c2 ); // true c1合并到c2中了,输出日志中动态更新起了作用,因此是持久化对象C2
            
            System.out.println( session.contains( c1 ) ); // false
            System.out.println( session.contains( c2 ) ); // true
            
        }
        
        /** 使用 saveOrUpdate 方法执行 更新操作,saveOrUpdate的操作条件 取决于映射文件中的unsaved-value属性的属性值*/
        public @Test void testUpdate4() {
            
            Session session = factory.openSession();
            Customer c = session.find( Customer.class ,  1 ); //  持久化状态
            session.close(); // 游离状态
            
            System.out.println( "id : " + c.getId() );
            
            String nickname = c.getNickname() ;
            c.setNickname( "三丰".equals( nickname ) ? "君宝" : "三丰" );
            
            session = factory.openSession();//重新开启一个session
            
            session.getTransaction().begin();
            
            // <id name="id" type="integer" column="id" unsaved-value="null" >
            // 取决于 c.id 是否是 null ,如果 id 是 null 就执行 insert ,否则执行 update
            session.saveOrUpdate( c ); // 执行 update 操作,将 游离状态的对象  转换到 持久化状态
            
            session.getTransaction().commit();
            
        }
        
        /** 使用 saveOrUpdate 方法执行 保存操作 */
        public @Test void testSave() {
            
            /*
            Session session = factory.openSession();
            Customer c = session.find( Customer.class ,  1 ); //  持久化状态
            session.close(); // 游离状态
            
            c.setId( null ); //等价于new一个新的对象
            c.setEmail( "zhangwuji@wudang.com" );
            c.setNickname( "曾阿牛" );
            */
            
            Customer c = new Customer();
            
            c.setEmail( "yinsusu@tianying.com" );
            c.setPassword( "hello2017" );
            
            Date birthdate = null ;
            c.setBirthdate( birthdate );
            c.setGender( '女' );
            
            c.setNickname( "素素" );
            c.setMarried( false );
            
            Session session = factory.openSession();
            
            session.getTransaction().begin();
            
            // <id name="id" type="integer" column="id" unsaved-value="null" >
            // 取决于 c.id 是否是 null ,如果 id 是 null 就执行 insert ,否则执行 update
            session.saveOrUpdate( c ); // 执行 insert 操作,对象 进入 持久化状态
            
            session.getTransaction().commit();
            
        }
        
        public @After void destory(){
            factory.close();
        }
    
    }

    更新操作有四种方法

    • 更新一个持久化状态的对象中的数据 后 同步到数据库中 ,但是不用 update 方法
    • 使用 update 方法将 游离状态 的对象 还原到 持久化状态
    • 使用 merge 方法 将一个 游离状态的 对象的 数据 合并到 与其id相等的持久化状态的对象中去
    • 使用 saveOrUpdate 方法执行 更新操作,saveOrUpdate的操作条件 取决于映射文件中的unsaved-value属性的属性值

    可以在映射文件中配置dynamic-update属性来实现动态更新

        <class name="ecut.session.entity.Customer" table="t_customer" dynamic-insert="true" dynamic-update="true" >

    saveOrUpdate也可以完成插入操作

    在映射文件中需要在id标签中指定unsaved-value属性的属性值,来决定什么时候执行插入操作什么时候执行更新操作

    <!-- 对于 与 数据库主键 对应的 对象标识符属性 来说,要单独使用 id 标签来映射  unsaved-value 默认是null 当id是null的时候执行插入操作,当id不是null时候执行update操作-->
            <id name="id" type="integer" column="id" unsaved-value="null" >
                <generator class="increment" /> <!-- 由 hibernate 提供的 对象标识符 生成策略 -->
            </id>

    转载请于明显处标明出处:

    https://www.cnblogs.com/AmyZheng/p/9313649.html

  • 相关阅读:
    Java 文件操作大全
    JAVA 环境变量配置
    Spring MVC 环境搭建(maven+SpringMVC+mybatis+Freemarker)
    maven的安装,maven库配置和Eclipse插件的安装
    maven web项目不能创建src/main/java等文件夹的问题
    Java 高效检查一个数组中是否包含某个值
    java发送http的get、post请求
    Timequest静态时序分析(STA)基础
    QuartusII Design partion and logic lock
    FPGA优化之高扇出
  • 原文地址:https://www.cnblogs.com/AmyZheng/p/9313649.html
Copyright © 2020-2023  润新知