【Java中级】7.0 SSH之Hibernate框架(三)——Log4j的使用及Hibernate核心API

百度百科——Hibernate

1.0 Log4j

学习本章内容之需要用到常用的日志工具类——Log4j。

1.1 平时可见的学习资料中,都是用的log4j 1.x版本

这次我们都使用较新的技术—— log4j 2.x版本

1.2 log4j 2.x版本不再支持像1.x中的.properties后缀的文件配置方式

2.x版本配置文件后缀名只能为".xml",".json"或者".jsn".

系统选择配置文件的优先级(从先到后)如下:
.classpath下的名为log4j2-test.json 或者log4j2-test.jsn的文件.
.classpath下的名为log4j2-test.xml的文件.
.classpath下名为log4j2.json 或者log4j2.jsn的文件.
.classpath下名为log4j2.xml的文件.

1.3 我们一般默认使用log4j2.xml进行命名。

如果本地要测试,可以把log4j2-test.xml放到classpath,而正式环境使用log4j2.xml,则在打包部署的时候不要打包log4j2-test.xml即可。

1.4根节点Configuration有两个属性:status和monitorinterval
  • 有两个子节点:Appenders和Loggers(可以定义多个Appender和Logger).

status用来指定log4j本身的打印日志的级别.
monitorinterval用于指定log4j自动重新配置的监测间隔时间,单位是s,最小是5s.

1.5 Appenders节点,常见的有三种子节点:Console、RollingFile、File.
  • Console节点用来定义输出到控制台的Appender.

    • name:指定Appender的名字.
    • target:SYSTEM_OUT 或 SYSTEM_ERR,一般只设置默认:SYSTEM_OUT.
    • PatternLayout:输出格式,不设置默认为:%m%n.
  • File节点用来定义输出到指定位置的文件的Appender.

    • name:指定Appender的名字.
    • fileName:指定输出日志的目的文件带全路径的文件名.
    • PatternLayout:输出格式,不设置默认为:%m%n.
      参考格式为:
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n" />
  • RollingFile节点用来定义超过指定大小自动删除旧的创建新的的Appender.
    • name:指定Appender的名字.
    • fileName:指定输出日志的目的文件带全路径的文件名.
    • PatternLayout:输出格式,不设置默认为:%m%n.
    • filePattern:指定新建日志文件的名称格式.
    • Policies:指定滚动日志的策略,就是什么时候进行新建日志文件输出日志.
    • TimeBasedTriggeringPolicy:Policies子节点,基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour。modulate=true用来调整时间:比如现在是早上3am,interval是4,那么第一次滚动是在4am,接着是8am,12am...而不是7am.
    • SizeBasedTriggeringPolicy:Policies子节点,基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小.
    • DefaultRolloverStrategy:用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性)。
1.6 Loggers节点,常见的有两种:Root和Logger.
  • Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出

    • level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF.
    • AppenderRef:Root的子节点,用来指定该日志输出到哪个Appender.
  • Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。

    • level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF.
    • name:用来指定该Logger所适用的类或者类所在的包全路径,继承自Root节点.
    • AppenderRef:Logger的子节点,用来指定该日志输出到哪个Appender,如果没有指定,就会默认继承自Root.如果指定了,那么会在指定的这个Appender和Root的Appender中都会输出,此时我们可以设置Logger的additivity="false"只在自定义的Appender中进行输出。
1.7 关于日志level.

共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF.

  • All:最低等级的,用于打开所有日志记录.
  • Trace:是追踪,就是程序推进以下,你就可以写个trace输出,所以trace应该会特别多,不过没关系,我们可以设置最低日志级别不让他输出.
  • Debug:指出细粒度信息事件对调试应用程序是非常有帮助的.
  • Info:消息在粗粒度级别上突出强调应用程序的运行过程.
  • Warn:输出警告及warn以下级别的日志.
  • Error:输出错误信息日志.
  • Fatal:输出每个严重的错误事件将会导致应用程序的退出的日志.
  • OFF:最高等级的,用于关闭所有日志记录.

程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少。

我的log4j2.xml文件放在sec/resource目录下,配置内容如下:

<?xml version="1.0" encoding="UTF-8"?>


<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出 -->
<!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数 -->
<configuration status="OFF" monitorInterval="30">
    <!--先定义所有的appender -->
    <appenders>
        <!--这个输出控制台的配置 -->
        <console name="Console" target="SYSTEM_OUT">
            <!--输出日志的格式 -->
            <PatternLayout
                pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" />
        </console>
        <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用 -->
        <File name="log" fileName="log/test.log" append="false">
            <PatternLayout
                pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n" />
        </File>
        <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档 -->
        <!-- <RollingFile name="RollingFileInfo" fileName="${sys:user.home}/logs/info.log" 
            filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log"> -->
        <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
        <!--<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" /> -->
        <!--<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" /> -->
        <!--<Policies> <TimeBasedTriggeringPolicy /> <SizeBasedTriggeringPolicy 
            size="100 MB" /> -->
        <!--</Policies> -->
        <!--</RollingFile> -->
        <!--<RollingFile name="RollingFileWarn" fileName="${sys:user.home}/logs/warn.log" 
            filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log"> -->
        <!--<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY" /> -->
        <!--<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" /> -->
        <!--<Policies> <TimeBasedTriggeringPolicy /> <SizeBasedTriggeringPolicy 
            size="100 MB" /> -->
        <!--</Policies> --><!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
        <!--<DefaultRolloverStrategy max="20" /> -->
        <!--</RollingFile> -->
        <!--<RollingFile name="RollingFileError" fileName="${sys:user.home}/logs/error.log" 
            filePattern="${sys:user.home}/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log"> -->
        <!--<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY" /> -->
        <!--<PatternLayout pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" /> -->
        <!--<Policies> <TimeBasedTriggeringPolicy /> -->
        <!--<SizeBasedTriggeringPolicy size="100 MB" /> -->
        <!--</Policies> -->
        <!--</RollingFile> -->
    </appenders>
    <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->
    <loggers>
        <!--过滤掉spring和mybatis的一些无用的DEBUG信息 -->
        <logger name="org.springframework" level="INFO"></logger>
        <logger name="org.mybatis" level="INFO"></logger>
        <root level="Info">
            <appender-ref ref="Console" />
            <appender-ref ref="RollingFileInfo" />
            <appender-ref ref="RollingFileWarn" />
            <appender-ref ref="RollingFileError" />
        </root>
    </loggers>
</configuration>
2.0 Configuration

说明:Hibernate的配置对象

1.0 Configuration 类的作用是对Hibernate 进行配置,以及对它进行启动。
2.0 在Hibernate 的启动过程中,Configuration 类的实例首先定位映射文档的位置,读取这些配置,然后创建一个SessionFactory对象。
3.0 虽然Configuration 类在整个Hibernate 项目中只扮演着一个很小的角色,但它是启动hibernate 时所遇到的第一个对象。

所以,Configuration的作用就2个:

2.1 加载核心配置文件

如果是一个属性文件,hibernate.properties:

Configuration cfg = new Configuration();

属性文件无法手动加载映射,可以通过如下代码实现:

        Configuration  configuration = new Configuration().configure();
        //手动加载映射
        configuration.addResource("com/edp/learn/Customer.hbm.xml");
2.2 手动加载映射文件
// 手动加载映射
configuration.addResource("com/edp/learn/Customer.hbm.xml" );
3.0 SessionFactory
3.1 基本说明

说明:Session工厂

1.0 SessionFactory接口负责初始化Hibernate。
2.0 它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式
3.0 需要注意的是SessionFactory并不是轻量级的,因为一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。

SessionFactory内部维护了Hibernate的连接池和Hibernate的二级缓存(目前企业中一般不用)。是线程安全的对象,一个项目创建一个对象即可。

3.2 配置连接池

当然,我们可以自己配置连接池。
C3P0:C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等。

       <!-- 配置C3P0连接池 -->
       <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
       <!--在连接池中可用的数据库连接的最少数目 -->
       <property name="hibernate.c3p0.min_size">5</property>
       <!--在连接池中所有数据库连接的最大数目 -->
       <property name="hibernate.c3p0.max_size">20</property>
       <!--设定数据库连接的过期时间,以秒为单位, 如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
       <property name="hibernate.c3p0.timeout">120</property>
       <!-- 当连接池里面的连接用完的时候,C3P0一下获取的新的连接数 -->
       <property name="hibernate.c3p0.acquire_increment">2</property>
       <!-- 每次都验证连接是否可用 -->
       <property name="hibernate.c3p0.validate">true</property>
       <!--每3000秒检查所有连接池中的空闲连接 以秒为单位 -->
       <property name="c3p0.idle_test_period">3000</property>

当然,在之前需要导入C3P0的jar包:


16102290-2165b73ad9a08bae.png
image.png

将这三个包复制到项目中的lib目录中并导入:


16102290-b7f7066b44d4b79e.png
image.png

运行结果如下:


16102290-7c6f7f1d98c72790.png
image.png

可以看出,标线处开始启动C3P0。


16102290-ef59e01b06c77849.png
image.png
3.3 SessionFactory工厂方法,创建一次即可
  1. 既然创建一次,就需要编写抽取工具类。
    在com.edp.hibernate.utils路径下新建HibernateUtils.java


    16102290-adc1c42a3cc1ea35.png
    image.png

    16102290-d0fe3da533ce242c.png
    image.png

    16102290-b41c53e518847420.png
    image.png

    HibernateUtils.java:

import org.hibernate.Session;

/**
 * 
 * @author EdPeng
 * @version 创建时间 2020年1月23日上午12:39:24
 * 类说明 Hibernate工具类
 */

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtils {
    public static final Configuration cfg;
    public static final SessionFactory sf;

    static {
        cfg = new Configuration().configure();
        sf = cfg.buildSessionFactory();
    }

    public static Session openSession() {
        return sf.openSession();
    }
}

在com.edp.hibernate.demo1路径下新建HibernateUtils.java
代码如下:

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.edp.hibernate.utils.HibernateUtils;

/**
 * 
 * @author EdPeng
 * @version 创建时间 2020年1月23日上午12:43:16 
 * 类说明 Hibernate的工具类的测试
 */
public class HibernateDemo2 {
    @Test
    public void demo1() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

        Customer customer = new Customer();
        customer.setCust_name("王二小");
        session.save(customer);
        
        txTransaction.commit();
        session.close();
    }
}

这样就能做到不重复新建SessionFactory对象。

4.0 Session

相当于JDBC中的Connection对象,是连接对象。代表Hibernate和数据库,建立起连接,是非线程安全的。是与数据库交互的桥梁。

  1. Session接口负责执行被持久化对象的CRUD操作(CRUD的任务是完成与数据库的交流,包含了很多常见的SQL语句)。
  2. 但需要注意的是Session对象是非线程安全的。
  3. 同时,Hibernate的session不同于JSP应用中的HttpSession。这里当使用session这个术语时,其实指的是Hibernate中的session,而以后会将HttpSession对象称为用户session。
4.1 Session中的API
  1. 保存方法:

Serializable save(Object obj);

  1. 查询方法:

T get(Class c,Serializable id);
T load(Class c,Serializable id);

  1. 修改方法

void update(Object obj);

  1. 删除方法

void delete(Object obj);s

  1. 保存或更新

void saveOrUpdate(Object obj)
查询所有

在我们使用Hibernate的所有代码都可以共用一块模板:

@Test
    //查询
    public void demo2() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();
        //写自己的代码
        txTransaction.commit();
        session.close();
    }
4.2 get方法和load方法的区别?
16102290-2a175073148b8e00.png
image.png
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.edp.hibernate.utils.HibernateUtils;

/**
 * 
 * @author EdPeng
 * @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
 */
public class HibernateDemo2 {
    @Test
    // 查询
    // ******** get方法和load方法的区别
    public void demo2() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

        /**
         * get 方法 * 采用的是立即加载,执行到这行代码的的时候,就会马上发送SQL语句去查询。 * 查询或返回是真实对象本身。 *
         * 查询一个找不到的对象的时候,返回null。
         * 
         * load方法 * 采用的是延迟加载(lazy懒加载)。执行到这行代码的时候不会发送SQL语句。当真正使用这个对象的时候,才会发送SQL语句。 *
         * 查询后返回的是代理对象。javassist-3.24.0-GA.jar 利用第三方的javassist技术产生的代理。 *
         * 查询一个找不到的对象的时候,返回ObjectNotFoundException
         */

        // 使用get方法查询
        Customer customer = session.get(Customer.class, 1l);// 发送sql语句
        System.out.println(customer.toString());

        // 使用load方法查询
        Customer customer1 = session.load(Customer.class, 2l);
        System.out.println(customer1.toString());

        txTransaction.commit();
        session.close();
    }
}

查询结果:


16102290-dc8c74ca2050bad5.png
image.png
4.3 修改方法

void update(Object obj);
修改操作有2种方法。

1. 第一种,直接修改。
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.edp.hibernate.utils.HibernateUtils;

/**
 * 
 * @author EdPeng
 * @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
 */
public class HibernateDemo2 {
    @Test
    // 修改操作
    public void demo3() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

//      
        // 直接创建对象,进行修改
        Customer customer = new Customer();
        customer.setCust_id(1l);
        customer.setCust_name("张三丰");
        session.update(customer);
        // 先查询后修改(推荐)
//      Customer customer2 = session.get(Customer.class, 3l);
//      customer2.setCust_name("周伯通");
//      session.update(customer2);

        txTransaction.commit();
        session.close();
    }
}

执行之前的数据库:


16102290-977f8a037c97ccf8.png
image.png

执行结果:


16102290-41fbfa26a892c9d5.png
image.png

执行之后的数据库:
16102290-54e34d06c9c35d0f.png
image.png

可见,用着种方法,会默认把其他set方法设置为null,导致数据丢失。

2. 先查询,后修改。

我们一般推荐如下方法:

package com.edp.hibernate.demo1;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.edp.hibernate.utils.HibernateUtils;

/**
 * 
 * @author EdPeng
 * @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
 */
public class HibernateDemo2 {
    @Test
    // 修改操作
    public void demo3() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

//      
        // 直接创建对象,进行修改
//      Customer customer = new Customer();
//      customer.setCust_id(1l);
//      customer.setCust_name("张三丰");
//      session.update(customer);
        // 先查询后修改(推荐)
        Customer customer2 = session.get(Customer.class, 3l);
        customer2.setCust_name("周伯通");
        session.update(customer2);

        txTransaction.commit();
        session.close();
    }
}

执行前的数据库:


16102290-d1cb155974ecef7e.png
image.png

执行结果:


16102290-5204edf299f950c5.png
image.png

执行后的数据库:

16102290-bad5c3e6f6774116.png
image.png

所以再一次推荐修改操作为第二种: 先查询后修改(推荐)

4.4 删除方法

void delete(Object obj);
删除也有两种方法,一种是直接删除,一种是先查询后删除,同样我们推荐第二种方法。

1. 直接删除
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.edp.hibernate.utils.HibernateUtils;

/**
 * 
 * @author EdPeng
 * @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
 */
public class HibernateDemo2 {
    @Test
    //删除操作
    public void demo4() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

        //直接创建对象,删除
        Customer customer = new Customer();
        customer.setCust_id(4l);
        session.delete(customer);
        //先查询再删除(推荐) 级联删除必须先查询后删除
        //比如多表的映射,客户下面还有订单,建立1对多的关系,这样可以把客户及其订单全删掉。
//      Customer customer2 = session.get(Customer.class,5l);
//      session.delete(customer2);
        
        txTransaction.commit();
        session.close();
    }
}

报PersistenceException错误,并提示not-null property references a null or transient value,无法成功运行。原因在于在我们的数据库配置文件Customer.hbm.xml中,对

        <property name="cust_name" column="cust_name" length="32" not-null="true" unique="false" />

将其设置not-null设置为true,而我们的数据库是允许其为null,这里需要将所有的not-null属性设置为false,或者不设置not-null属性即可。
执行之前的数据库:


16102290-8a960631d1116143.png
image.png

执行结果:


16102290-6ac3ceaa5f647829.png
image.png

执行之后的数据库:
16102290-6e0a98895a49e345.png
image.png
2. 先查询后删除
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.edp.hibernate.utils.HibernateUtils;

/**
 * 
 * @author EdPeng
 * @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
 */
public class HibernateDemo2 {

    @Test
    //删除操作
    public void demo4() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

        //直接创建对象,删除
//      Customer customer = new Customer();
//      customer.setCust_id(1l);
//      session.delete(customer);
        //先查询再删除(推荐) 级联删除必须先查询后删除
        //比如多表的映射,客户下面还有订单,建立1对多的关系,这样可以把客户及其订单全删掉。
        Customer customer2 = session.get(Customer.class,5l);
        session.delete(customer2);
        
        txTransaction.commit();
        session.close();
    }
}

执行之前的数据库:


16102290-bb197443a8d2e2cd.png
image.png

执行结果:


16102290-8cb0f16375e2ad5c.png
image.png

执行之后的数据库:


16102290-13ae3349dea88875.png
image.png

同样,我们推荐第二种删除方法,因为第二种支持级联删除,联删除必须先查询后删除,比如多表的映射,客户下面还有订单,建立1对多的关系,这样可以把客户及其订单全删掉。
而第一种我们知道,会把没有写明的其他属性值重置为null,再进行相关操作,会删除关联信息,导致关联的其他表格数据无法被删除。

4.5 保存或更新方法

void saveOrUpdate(Object obj)

保存或更新方法也有两种,一种是直接通过setCust_name等方法添加字段,这是更新操作,另一种是通过setCust_id(7l)加其他set方法,实现保存(修改)操作。

1. 保存更新操作
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.edp.hibernate.utils.HibernateUtils;

/**
 * 
 * @author EdPeng
 * @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
 */
public class HibernateDemo2 {

    @Test
    // 保存或更新操作
    public void demo5() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

        // 直接添加,更新
        Customer customer = new Customer();
        customer.setCust_name("柯镇恶");
        session.saveOrUpdate(customer);
        // 有id,则是保存,id找不到则会报错
//      Customer customer2 = new Customer();
//      customer2.setCust_id(7l);
//      customer2.setCust_name("风清扬");
//      session.saveOrUpdate(customer2);

        txTransaction.commit();
        session.close();
    }
}

执行之前的数据库:


16102290-9b1ec5655525e0d3.png
image.png

执行结果:


16102290-ff6d90d0111e1e30.png
image.png

执行之后的数据库:
16102290-235b51169f32d979.png
image.png
2. 保存(修改)操作
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.edp.hibernate.utils.HibernateUtils;

/**
 * 
 * @author EdPeng
 * @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
 */
public class HibernateDemo2 {
    @Test
    // 保存或更新操作
    public void demo5() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

        // 直接添加,更新
//      Customer customer = new Customer();
//      customer.setCust_name("柯镇恶");
//      session.saveOrUpdate(customer);
        // 有id,则是更新,id找不到则会报错
        Customer customer2 = new Customer();
        customer2.setCust_id(7l);
        customer2.setCust_name("风清扬");
        session.saveOrUpdate(customer2);

        txTransaction.commit();
        session.close();
    }
}

执行之前的数据库:


16102290-d4f77b2d755e0915.png
image.png

执行结果:


16102290-64e629b98a072d33.png
image.png

执行之后的数据库:
16102290-796712aa00779784.png
image.png
4.6 查询所有

NativeQuery Session.createSQLQuery(String arg0);

1. 支持HQL语句查询,返回Query类型。
  • HQL:Hibernate Query Language 面向对象的查询语言
    代码演示:
import java.util.List;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.junit.Test;

import com.edp.hibernate.utils.HibernateUtils;

/**
 * 
 * @author EdPeng
 * @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
 */
public class HibernateDemo2 {
    @Test
    // 查询所有
    public void demo6() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

        // 接收HQL:Hibernate Query Language 面向对象的查询语言
        // 需要向createQuery方法传递一个HQL参数
                //返回Query类型
        Query query = session.createQuery("from Customer");
        List<Customer> list = query.list();
        for (Customer customer : list) {
            System.out.println(customer);
        }
        
        txTransaction.commit();
        session.close();
    }
}

数据库:


16102290-158d306b379bbb21.png
image.png

执行结果:


16102290-47d85f2c029c478a.png
image.png
2. 支持SQL语句查询,返回NativeQuery 类型(5.2之前使用SQLQuery类型)。

hibernate 5.2 之后,SQLQuery类已作废,用NativeQuery替代。


16102290-517c1b7cd590b895.png
image.png

将查询结果作为列表返回。如果查询每行包含多个结果,则结果将在Object[]的实例中返回。

示范代码:

import java.util.Arrays;
import java.util.List;

import org.hibernate.query.NativeQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.junit.Test;

import com.edp.hibernate.utils.HibernateUtils;

/**
 * 
 * @author EdPeng
 * @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
 */
public class HibernateDemo2 {
    @Test
    // 查询所有
    public void demo6() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

        // 接收HQL:Hibernate Query Language 面向对象的查询语言
        // 需要向createQuery方法传递一个HQL参数
//      Query query = session.createQuery("from Customer");
//      List<Customer> list = query.list();
//      for (Customer customer : list) {
//          System.out.println(customer);
//      }

        // 接收SQL
        NativeQuery nativeQuery= session.createSQLQuery("select * from cst_customer");
        List<Object[]> list2 = nativeQuery.list();
        for (Object[] objects : list2) {
            System.out.println(Arrays.toString(objects));
        }

        txTransaction.commit();
        session.close();
    }
}

执行结果为:


16102290-beed4b368d724e44.png
image.png
5.0 Transaction:事务对象

Hibernate中管理事务的对象,其中的API非常少。最常用的就以下两个方法:

commit(); 提交
rollback(); 回滚

  • Transaction 接口是一个可选的API,可以选择不使用这个接口,取而代之的是Hibernate 的设计者自己写的底层事务处理代码。
  • Transaction 接口是对实际事务实现的一个抽象,这些实现包括JDBC的事务、JTA 中的UserTransaction、甚至可以是CORBA 事务。
  • 之所以这样设计是能让开发者能够使用一个统一事务的操作界面,使得自己的项目可以在不同的环境和容器之间方便地移植。

没有配置C3P0,需要编写开启和提交代码,如果自带的连接池,Hibernate会帮我们自动开启和提交事务。

6.0 附录

最后,附上整个项目的目录和本章的完整代码:


16102290-adf0405f32cc17cf.png
image.png
import java.util.Arrays;
import java.util.List;

import org.hibernate.query.NativeQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.junit.Test;

import com.edp.hibernate.utils.HibernateUtils;

/**
 * 
 * @author EdPeng
 * @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
 */
public class HibernateDemo2 {
    @Test
    public void demo1() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

        Customer customer = new Customer();
        customer.setCust_name("王二小");
        session.save(customer);

        txTransaction.commit();
        session.close();
    }

    @Test
    // 查询
    // ******** get方法和load方法的区别
    public void demo2() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

        /**
         * get 方法 * 采用的是立即加载,执行到这行代码的的时候,就会马上发送SQL语句去查询。 * 查询或返回是真实对象本身。
         * *查询一个找不到的对象的时候,返回null。
         * 
         * load方法 * 采用的是延迟加载(lazy懒加载)。执行到这行代码的时候不会发送SQL语句。当真正使用这个对象的时候,才会发送SQL语句。 *
         * 查询后返回的是代理对象。javassist-3.24.0-GA.jar 利用第三方的javassist技术产生的代理。 *
         * 查询一个找不到的对象的时候,返回ObjectNotFoundException
         */

        // 使用get方法查询
        Customer customer = session.get(Customer.class, 1l);// 发送sql语句
        System.out.println(customer.toString());

        // 使用load方法查询
        Customer customer1 = session.load(Customer.class, 2l);
        System.out.println(customer1.toString());

        txTransaction.commit();
        session.close();
    }

    @Test
    // 修改操作
    public void demo3() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

//      
        // 直接创建对象,进行修改
//      Customer customer = new Customer();
//      customer.setCust_id(1l);
//      customer.setCust_name("张三丰");
//      session.update(customer);
        // 先查询后修改(推荐)
        Customer customer2 = session.get(Customer.class, 3l);
        customer2.setCust_name("周伯通");
        session.update(customer2);

        txTransaction.commit();
        session.close();
    }

    @Test
    // 删除操作
    public void demo4() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

        // 直接创建对象,删除
        Customer customer = new Customer();
        customer.setCust_id(4l);
        session.delete(customer);
        // 先查询再删除(推荐) 级联删除必须先查询后删除
        // 比如多表的映射,客户下面还有订单,建立1对多的关系,这样可以把客户及其订单全删掉。
//      Customer customer2 = session.get(Customer.class,5l);
//      session.delete(customer2);

        txTransaction.commit();
        session.close();
    }

    @Test
    // 保存或更新操作
    public void demo5() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

        // 直接添加,更新
//      Customer customer = new Customer();
//      customer.setCust_name("柯镇恶");
//      session.saveOrUpdate(customer);
        // 有id,则是更新,id找不到则会报错
        Customer customer2 = new Customer();
        customer2.setCust_id(7l);
        customer2.setCust_name("风清扬");
        session.saveOrUpdate(customer2);

        txTransaction.commit();
        session.close();
    }

    @Test
    // 查询所有
    public void demo6() {
        Session session = HibernateUtils.openSession();
        Transaction txTransaction = session.beginTransaction();

        // 接收HQL:Hibernate Query Language 面向对象的查询语言
        // 需要向createQuery方法传递一个HQL参数
//      Query query = session.createQuery("from Customer");
//      List<Customer> list = query.list();
//      for (Customer customer : list) {
//          System.out.println(customer);
//      }

        // 接收SQL
        NativeQuery nativeQuery= session.createSQLQuery("select * from cst_customer");
        List<Object[]> list2 = nativeQuery.list();
        for (Object[] objects : list2) {
            System.out.println(Arrays.toString(objects));
        }

        txTransaction.commit();
        session.close();
    }
}

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值