hibernate
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JaveEE架构中取代CMP,完成数据持久化的重任。
步骤:
创建表
Create database hibernate_day01;
Use hibernate_day01;
CREATE TABLE `cst_customer` (
`cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
`cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
`cust_user_id` bigint(32) DEFAULT NULL COMMENT '负责人id',
`cust_create_id` bigint(32) DEFAULT NULL COMMENT '创建人id',
`cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
`cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
`cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
`cust_linkman` varchar(64) DEFAULT NULL COMMENT '联系人',
`cust_phone` varchar(64) DEFAULT NULL COMMENT '固定电话',
`cust_mobile` varchar(16) DEFAULT NULL COMMENT '移动电话',
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=94 DEFAULT CHARSET=utf8;
引入Hibernate的jar包
创建实体
package com.itheima.domain;
public class Customer{
public Long getCust_id() {
return cust_id;
}
public void setCust_id(Long cust_id) {
this.cust_id = cust_id;
}
public String getCust_name() {
return cust_name;
}
public void setCust_name(String cust_name) {
this.cust_name = cust_name;
}
public Long getCust_user_id() {
return cust_user_id;
}
public void setCust_user_id(Long cust_user_id) {
this.cust_user_id = cust_user_id;
}
public Long getCust_create_id() {
return cust_create_id;
}
public void setCust_create_id(Long cust_create_id) {
this.cust_create_id = cust_create_id;
}
public String getCust_source() {
return cust_source;
}
public void setCust_source(String cust_source) {
this.cust_source = cust_source;
}
public String getCust_industry() {
return cust_industry;
}
public void setCust_industry(String cust_industry) {
this.cust_industry = cust_industry;
}
public String getCust_level() {
return cust_level;
}
public void setCust_level(String cust_level) {
this.cust_level = cust_level;
}
public String getCust_linkman() {
return cust_linkman;
}
public void setCust_linkman(String cust_linkman) {
this.cust_linkman = cust_linkman;
}
public String getCust_phone() {
return cust_phone;
}
public void setCust_phone(String cust_phone) {
this.cust_phone = cust_phone;
}
public String getCust_mobile() {
return cust_mobile;
}
public void setCust_mobile(String cust_mobile) {
this.cust_mobile = cust_mobile;
}
private Long cust_id;
private String cust_name;
private Long cust_user_id;
private Long cust_create_id;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_linkman;
private String cust_phone;
private String cust_mobile;
}
创建映射文件
<?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="com.itheima.domain.Customer" table="cst_customer">
<id name="cust_id" column="cust_id">
<!--主键生成策略-->
<generator class="native"/>
</id>
<property name="cust_name" column="cust_name"/>
<property name="cust_user_id" column="cust_user_id"/>
<property name="cust_create_id" column="cust_create_id"/>
<property name="cust_source" column="cust_source"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_linkman" column="cust_linkman"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
</class>
</hibernate-mapping>
映射文件中,主键的生成策略:
创建核心配置文件
<?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:///hibernate_day01</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<!-- 数据库的方言: -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Hibernate的可选项 -->
<!--显示sql语句-->
<property name="hibernate.show_sql">true</property>
<!--格式化sql语句-->
<property name="hibernate.format_sql">true</property>
<!--有表生成表,没表不做更改-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 加载映射 -->
<mapping resource="com/itheima/domain/Customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
编写代码
package com.itheima.test;
import com.itheima.domain.Customer;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class Demo1 {
@Test
public void testSave(){
//1.加载配置文件
Configuration config= new Configuration() .configure();
//2.使用sessionFactory
SessionFactory sessionFactory = config.buildSessionFactory();
//3使用sessionfactory 实例化session对象
Session session = sessionFactory.openSession();
//4.开启事务
Transaction tr=session.beginTransaction();
//5.编写保存的代码
Customer c=new Customer();
c.setCust_name("2");
c.setCust_phone("110");
session.save(c);
//6.提交事务
tr.commit();
//7.释放资源
session.close();
sessionFactory.close();
}
}
为了提高代码的复用性,抽取出工具类
Hibernate的工具类
package com.itheima.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/*hibernate框架的工具类*/
public class HibernateUtils {
//ctrl+shift+x
private static final Configuration CONFIG;
private static final SessionFactory FACTORY;
static {
//加载xml的配置文件
CONFIG=new Configuration().configure();
//构造工厂
FACTORY=CONFIG.buildSessionFactory();
}
//从工厂中获取Session对象
public static Session getSession(){
return FACTORY.openSession();
}
}
测试方法
public void run1(){
Session session=HibernateUtils.getSession();
Transaction tr=session.beginTransaction();
tr.commit();
session.close();
}
hibernate持久化对象状态的转换
持久化类:就是一个Java类,这个Java类与表建立了映射关系就可以称为是持久化类。
特点:唯一的标识OID,数据库通过主键,Java对象通过地址确定对象,持久化类通过唯一标识OID确定记录。
Hibernate为了管理持久化类,将持久化类分成了三个状态:
- 瞬时态:Transient Object
没有持久化表示OID,没有被纳入到Session对象的管理
- 持久态:Persistent Object
有持久化标识OID,已经被纳入Session对象的管理
- 托管态:Detached Object
有持久化表示OID,没有被纳入到Session对象的管理
package com.itheima.test;
import com.itheima.domain.User;
import com.itheima.utils.HibernateUtils;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import java.io.Serializable;
public class Demo1 {
@Test
public void run1(){
Session session=HibernateUtils.getSession();
Transaction tr=session.beginTransaction();
//瞬时态,没有oid的值,没有session管理
User user=new User();
user.setName("小风");
user.setAge(28);
//使用session保存用户
//user已经存在id的值,默认情况下,把user对象也保存到session的缓存中
Serializable id=session.save(user);
System.out.println("主键的值"+id);
tr.commit();
//托管态,session销毁,缓存没有了,session不管理user对象
session.close();
}
}
三个状态对象之间的转换
持久化对象,有自动更新数据库的能力
public void run2(){
Session session=HibernateUtils.getSession();
Transaction tr=session.beginTransaction();
User user=session.get(User.class,1);
System.out.println(user.getName());
//对数据库进行跟新
user.setName("小天");
//正常编写代码
//session.update(user);
tr.commit();
session.close();
}
Hibernate的缓存
缓存是一块内存空间,将数据源中的数据存放到缓存中,再次获取的时候,直接从缓冲中获取。
- 一级缓存:自带,session级别的缓存
- 二级缓存:sessionFactory级别的缓存
@Test
public void run2(){
Session session=HibernateUtils.getSession();
Transaction tr=session.beginTransaction();
//查询数据库,session缓存区域获取持久化对象的值,
User user=session.get(User.class,1);
System.out.println(user.getName());
//修改换从区域中的数据,此时,session的缓存区域为新值,
// 而session的快照区域,也就是副本,还是原来的值
user.setName("小天");
//提交之前,自己对比缓存和快照区的数据是否一致,如果不一致,把快照区域值进行跟新
tr.commit();
//session销毁了,任何内容都没有了
session.close();
}
控制Session的几种方法:
Session.clear();清空缓存
Session.evict(Object entity);从一级缓存中清除指定对象
Session.flush();刷出缓存
事务
事务就是逻辑上的一组操作,组成事务的各个执行单元,操作要么全部成功,要么全部失败。
特性:
- 原子性:事务不可分割
- 一致性:事务执行前后数据的完整性保持一致
- 隔离性:一个事务执行的过程中,不应该受到其他事务的干扰
- 持久性:事务一旦提交,数据就永远保持到数据库中
如果不考虑隔离性,会引发一些读的问题:
- 脏读:一个事务读到了另一个事务未提交的数据
- 不可重复读:一个事务读到了另一个事务已经提交的update数据,导致多次查询结果不一致
- 虚读:一个事务读到了另一个事务已经提交的insert数据,导致多次查询结果不一致
如果想在hibernate的框架中来设置隔离级别,需要hibernate.cfg.xml的配置文件通过标签来设置
hibernate.connection.ioslation=1;2;4;8来配置。
丢失更新问题的产生和解决
如果两个事务同时对某一条记录做修改,就会引发丢失更新问题。
解决方法:
- 悲观锁:采用的是数据库提供的一种锁机制,如果采用了这种机制,在sql语句的后面添加for update的字句
- 乐观锁:给表结构增加一个字段version=0,默认值是0
<!--乐观锁,使用version标签-->
<version name="version"/>
绑定本地的session