我是如何学习Hibernate的(二)

前述

在前一篇博客中,我记录了Hibernate的环境的搭建,并且熟悉了一次Hibernate执行的过程。我在后面的博客中,会记录更多关于hibernate中的知识点。总共会有以下所有内容:

  • 整合log4j
  • 配置文件
  • API
  • Hibernate CRUD操作
  • PO对象的操作
  • 一级缓存
  • 二级缓存
  • 关联关系
  • 抓取策略
  • HQL
  • 事务隔离

一.整合log4j

log4j是Apache组织的一个开源项目,用于将日志信息输送到控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器。我们可以控制每一条日志的输出格式,还可以通过定义日志信息的级别,而这一切操作,都可以通过配置文件来完成。

  • 引入jar包:到log4j官网就可以下载到。
  • 配置文件log4j.properties
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    #The five logging levels used by Log are (in order):  
    #
    #1. DEBUG (the least serious)
    #2. INFO
    #3. WARN
    #4. ERROR
    #5. FATAL (the most serious)

    #Set root logger level to INFO and append to stdout
    log4j.rootLogger=INFO,stdout,file
    #设置log的级别为INFO意味着INFO级别以下如DEBUG的信息不会输出
    #其中,Log4j提供的appender有以下几种:
    #org.apache.log4j.ConsoleAppender(控制台),
    #org.apache.log4j.FileAppender(文件),
    #org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),
    #org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件),
    #org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

    #其中,Log4j提供的layout有以几种:
    #org.apache.log4j.HTMLLayout(以HTML表格形式布局),
    #org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
    #org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
    #org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

    #Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下:
    #%m 输出代码中指定的消息
    #%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
    #%r 输出自应用启动到输出该log信息耗费的毫秒数
    #%c 输出所属的类目,通常就是所在类的全名
    #%t 输出产生该日志事件的线程名
    #%n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”
    #%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2016年5月1日 22:10:28,921
    #%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)

    #stdout
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=[%p]%-d{yyyy-MM-dd HH\:mm\:ss}[%c\:%L] %m%n

    #file
    log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.file.File=/output.log
    log4j.appender.file.DatePattern='.'yyyy-MM-dd
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=[%p]%-d{yyyy-MM-dd HH\:mm\:ss}[%c\:%L] %m%n
    #log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
    #log4j.appender.file.File=/output.html
    #log4j.appender.file.DatePattern='.'yyyy-MM-dd
    #log4j.appender.file.layout=org.apache.log4j.HTMLLayout
    #log4j.appender.file.layout.ConversionPattern=[%p]%-d{yyyy-MM-dd HH\:mm\:ss}[%c\:%L] %m%n

    #Print only messages of level ERROR or above in the package noModule.
    log4j.logger.noModule=INFO

二.核心配置文件hibernate.cfg.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<hibernate-configuration>
<session-factory>
<!-- 配置Hibernate基本信息 -->

<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/hibernate001</property>
<property name="connection.username">root</property>
<property name="connection.password">jessyon6233834</property>

<!-- 配置Hibernate方言 -->
<property name="hibernate.dialect ">
org.hibernate.dialect.MySQLDialect
</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 可选属性 -->
<property name="hibernate.show_sql">true</property>

<!-- 格式化sql -->
<property name="hibernate.format_sql">true</property>

<!-- 通知Hibernate加载哪些配置-->
<mapping resource="com/hibernate3/Customer.hbm.xml" />
<mapping resource="com/hibernate3/Order.hbm.xml"/>

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

Hibernate映射配置文件

1
2
3
4
5
6
7
8
9
10
<hibernate-mapping>
<class name="com.hibernate3.Customer" table="customer">
<id name="id" column="id" >
<generator class="native" />
</id>

<property name="name" column="name" type="string" length="20"/>
<property name="age" column="age"></property>
</class>
</hibernate-mapping>

三.常用API

  1. 读取并解析配置文件 Configuration conf = new Configuration().configure();
  2. 读取并解析映射信息,创建SessionFactory SessionFactory sf = conf.buildSessionFactory();
  3. 打开Session Session session = sf.openSession();
  4. 开始一个事务(增删改操作必须,查询操作可选) Transaction tx = session.beginTransaction();
  5. 数据库操作 session.save(user);//或其它操作
  6. 提交事务(回滚事务) tx.commit();(tx.rollback();)
  7. 关闭session session.close();
  • Configuration是默认加载hibernate.cfg.xml这个文件的,但也提供了重载的方法
    public Configuration configure(String resource)
    public Configuration configure(URL url)
    public Configuration configure(File configFile)

  • SessionFactiory:Configuration的实例会根据当前的配置信息,构造SessionFactory实例。SessionFactory是线程安全的,一般情况下一个应用中一个数据库共享一个SessionFactory实例。

  • Hibernate的SessionFactory接口提供Session类的实例,Session类用于完成对数据库的操作。由于SessionFactory实例是线程安全的(而Session实例不是线程安全的),所以每个操作都可以共用同一个SessionFactory来获取Session。
    从XML文件读取配置信息构建SessionFactory
    Configuration config = new Configuration().configure();
    SessionFactory sessionFactory = config.buildSessionFactory();

  • Session:一般的持久化方法(CRUD)都是通过Session来调用的,Session是非线程安全的。
    Session的创建与关闭 :Session是一个轻量级对象,通常将每个Session实例和一个数据库事务绑定,也就是每执行一个数据库事务,都应该先创建一个新的Session实例,在使用Session后,还需要关闭Session。
    Session的创建
    创建SessionFactory后,就可以通过SessionFactory创建Session实例,通过SessionFactory创建Session实例的代码如下。
    Session session=sessionFactory.openSession();
    创建Session后,就可以通过创建的Session进行持久化操作了。
    Session的关闭
    在创建Session实例后,不论是否执行事务,最后都需要关闭Session实例,释放Session实例占用的资源。
    关闭Session实例的代码如下:
    session.close();
    下面来看一下:getCurrentSession 与 openSession() 的区别
    1.getCurrentSession创建的session会和绑定到当前线程,而openSession不会。
    2 getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSession必须手动关闭
    3.getCurrentSession () 使用当前的session,openSession() 重新建立一个新的session
    这里getCurrentSession本地事务(本地事务:jdbc)时 要在配置文件里进行如下设置
    如果使用的是本地事务(jdbc事务)

1
<property name="hibernate.current_session_context_class">thread</property>

如果使用的是全局事务(jta事务)

1
<property name="hibernate.current_session_context_class">jta</property>

openSession() 与 getCurrentSession() 有何不同和关联呢?
在SessionFactory启动的时候Hibernate会根据配置创建相应的CurrentSessionContext,在getCurrentSession()被调用的时候,实际被执行的方法是CurrentSessionContext.currentSession()。在currentSession()执行时,如果当前Session为空,currentSession会调用SessionFactory的openSession所以getCurrentSession()对于avaEE来说是更好的获取Session的方法。

  • Transaction: hibernate把AutoCommit关掉了,所以如果想要进行数据操作,又不开启事务的话,数据库就不会有任何改变。