一. 实体类的映射文件
文件名:实体类名.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 提示去哪复制?
Web App Library -> hibernate-core-5.2.10.Final.jar -> org.hibernate -> hibernate-mapping-3.0.dtd
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 配置表与实体类的关系
name:实体类的全类名
table:表名
package:包名 填上后 下面写全类名时可以省略包名
-->
<hibernate-mapping package="com.commander">
<class name="实体类全限定名" table="数据库中对应的表名">
<!--
id:表示主键
注意:没有主键不能使用hibernate
name:表示类中的成员变量名
column:表示这个成员变量所代表的表中的字段名
-->
<id name="实体类中与数据库中对应的主键名" column="数据库中的主键名">
<!-- 主键的生成策略 这里用主键自增策略 -->
<generator class="主键生成策略(native)"></generator>
</id>
<!--
property:表示除主键以外的属性
-->
<property name="实体类属性名" column="数据库中对应表中的字段名"></property>
</class>
</hibernate-mapping>
主键的分类:
规则:不能重复 不能修改
1.自然主键
表里有一个属性 符合主键的规则
就直接使用这个字段作为主键
2.代理主键
表里面没有一个字段 符合主键的规则
自己创建id 作为表的主键 这个键就叫代理主键
主键生成策略(七种)
1. identity
主键自增 使用数据库中的主键自增
插入时 打印sql时 不会插入id
2. increment
主键自增 由hibernate来管理
插入数据时 会先去数据库中查询当前最大id
然后把查出来的id+1 再插入数据
3. uuid
全球不重复的唯一标识(32位 字符串)
注意:id必须使用字符串类型
4. native(最常用的 三合一)
根据你使用数据库类型来选择使用
下面三个策略之一
所有数据库不是支持identity 就是支持序列
identity + sequence + hilo
5. hilo(高低位算法)
将主键交给hibernate处理 使用自己的算法 帮你维护主键
6. assigned
由你自己维护主键 插入数据时需要有主键
使用的代理主键
7. sequence oracle数据库默认的
二. 主配置文件
文件名: hibernate.cfg.xml
<!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 >
<!-- hibernate数据库配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate01</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<!-- 加载mysql的方言包 limit -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<!-- 开启打印sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 开启格式化sql语句 -->
<property name="hibernate.format_sql">true</property>
<!-- 自动更新表结构 没有表会帮你创建出来表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!--
设置数据库隔离级别
默认隔离级别是4 (1|2|4|8)
#hibernate.connection.isolation 4
1.脏读
2.不可重复读
3.幻读
隔离级别
READ UNCOMMITED 读未提交 123 - 1
READ COMMITED 读已提交 23 - 2
REPEATABLE READ 可重复读 3 - 4
Serializable 串行化 都能避免 - 8
隔离级别使用1个字节来存储的
0001
0010
0100
1000
-->
<property name="hibernate.connection.isolation">4</property>
<!-- 自动生成表结构
(etc/hibernate.properties)
update(常用)
自动生成表结构 如果映射文件和数据库表不对应 将会修改你的表字段
但是原来表的自断不会改变 会新增字段
create
每次运行都会创建一个新的表出来(数据丢失)
create-drop
每次运行都会创建一个新的表出来
每次运行结束都会把表删了
validate
每次都会验证你的表结构
如果实体类与映射文件不同 将会抛出一个异常
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!--
注意:使用getCurrentSession方法 必须配置
配置的是让当前的session与线程绑定
-->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 映射数据库表对应的映射文件的路径
路径从包名开始写 并且中间使用的是反斜杠/
-->
<mapping resource="com/commander/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
三. 两种从session工厂中获取session的方法
1. openSession
是创建一个全新的session
Configuration configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
2.getCurrentSession
获取的是当前使用的session
Configuration configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
注意: 使用该方法 必须在主配置文件中配置一下 在<session-factory>标签内中加上下面一条
<property name="hibernate.current_session_context_class">thread</property>
四.hibernate操作对象的三种状态
1.瞬时态
没有ID 没有跟session产生关系
2.持久态
有ID 跟session产生了关系
3.游离态
有ID 没有跟session产生关系
hibernate在操作数据库时 就是将持久态的对象同步到数据库
比如:
@Test
public void fun1() {
//保存一个用户
Session session = HibernateUitl.getOpenSession();
Transaction transaction = session.beginTransaction();
User user = new User();//瞬时态
user.setUsername("taylor");
session.save(user);//持久态
transaction.commit();
session.close();//游离态
}
hibernate会在你提交事务之后 把持久态的对象同步到数据库
@Test
public void fun2() {
Session session = HibernateUitl.getOpenSession();
Transaction transaction = session.beginTransaction();
//使用get方法查询一个对象
User user = session.get(User.class, 1);
user.setUsername("swift");
transaction.commit();
session.close();
}
存储时 有两种:
缓存(读写速度快 效率高)
硬盘(读写文件 速度慢)
当你调用get方法去数据库查询时 数据库给你返回的结果集 会被hibernate封装成对象
并且会在缓存中保存一份
当你再次用get方法查询时 hibernate会先到缓存中去查找 有没有该id的对象
有就直接返回缓存中的对象
没有就使用sql语句去操作数据库查询
@Test
public void fun3() {
Session session = HibernateUitl.getOpenSession();
Transaction transaction = session.beginTransaction();
User user1 = session.get(User.class, 1);
User user2 = session.get(User.class, 1);
User user3 = session.get(User.class, 1);
User user4 = session.get(User.class, 1);
User user5 = session.get(User.class, 1);
System.out.println(user2 == user5);
transaction.commit();
session.close();
}
测试时只打印一次sql查询语句
快照:
用get方法查询时
hibernate会把结果集保存到缓存中一份 也会在快照中保存一份
当你最终提交事务操作数据库的时候hibernate会对比缓存与快照中的数据
一样就不存了 反之会同步到数据库
@Test
public void fun4() {
Session session = HibernateUitl.getOpenSession();
Transaction transaction = session.beginTransaction();
User user = session.get(User.class, 1);
user.setUsername("taylorSwift");
user.setUsername("mayDay");
session.update(user);
transaction.commit();
session.close();
}
sql语句会打印两次 : select 和 update