模型类的规范:
1 必须有默认构造方法, 查询时把数据表中的一条数据映射成一个对象时需要使用默认构造器来创建对象
2 必须提供一个OID, 作为对象的主键(就是userId了)
3 属性必须私有化封装, 就是提供set跟get方法
4 不要使用final来修饰模型类中的成员, 如果是final修饰在后续要讲到的延迟加载无法实现
5 最好使用封装类,
基本类型 int 默认值是0
包装类 Integer 默认值是null
假如该值本来没有填写, 由于是基本类型, 系统将默认值0代替它而不是null, 因而你无法判断是填写了0还是默认值
映射文件详解:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
package: 指定当前映射文件的实体类的包路径
-->
<hibernate-mapping package="com.rl.hiber.model">
<!--
class: 实体类名
table: 对应数据库表名
-->
<class name="User" table="t_user">
<!--
设置主键
generator: 主键的生成策略(后续再介绍)
-->
<id name="userId" column="user_id">
<!--
identity(常用): 使用mysql的自增策略, 这种自增没有并发问题, 前提是model的oid是数值类型, 所映射的column也是数值类型
native(比较智能): 根据数据库的方言来翻译, 自动翻译成identity(mysql)或sequence(oracle)
uuid(有大量使用, 由于没有锁机制, 性能较高): 没有并发问题, 按照自己的策略生成一个32位的字符串, 主键不重复, 前提是主键(oid)必须是字符串类型
assigned: 手动指定id(在实际项目中不使用)
increment: 主键自动自增(在实际项目中不去使用, 因为有并发安全性问题)
-->
<generator class="identity"></generator>
</id>
<!--
name: 实体类的属性名
column: 数据库表中的列名
可选属性:
type: 设置字段类型(一般不用设置)
length: 设置字段长度
not-null: 设置非空约束
unique-key: 设置唯一键约束
-->
<property name="uname" column="uname"></property>
<property name="gender" column="gender"></property>
<property name="birthday" column="birthday"></property>
</class>
</hibernate-mapping>
环境初始化详解:
Configuration: 创建Hibernate配置对象, 读取hibernate.cfg.xml文件初始化环境
ServiceRegistry: 注册hibernate属性信息
SessionFactory: Session工厂类, 这个类是一个重量级的对象, 线程安全的, 负责创建Session, 这个对象在服务器启动的时候创建一个即可
Session: 是一次和数据库的会话, 但是不一定是一次连接, Session给我们提供了很多操作数据库的方法, 操作的是对象, 影响的是数据库
Transaction: 事务对象, 控制我们Session对象数据库操作的事务
封装一个工具类以简化代码:
HibernateUtil类:
package com.rl.hiber.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public class HibernateUtil {
private static SessionFactory sf;
//静态块
static {
Configuration cfg = new Configuration();
cfg.configure("hibernate.cfg.xml");
ServiceRegistry sr = new StandardServiceRegistryBuilder().applySettings(cfg.getProperties()).build();
sf = cfg.buildSessionFactory(sr);
}
public static SessionFactory getSessionFactory() {
return sf;
}
public static Session getSessoion() {
return sf.openSession();
}
public static void closeSession(Session session) {
session.close();
}
public static void closeResource(Session session) {
session.close();
sf.close();
}
}
修改测试代码:
package com.rl.hiber.test;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.junit.Test;
import com.rl.hiber.model.User;
import com.rl.hiber.utils.HibernateUtil;
public class TestHibernate {
@Test
public void test2() {
//获取session
Session session = HibernateUtil.getSessoion();
//需要先开启事务
Transaction tx = session.beginTransaction();
try {
//创建对象
User user = new User();
user.setUname("zhangsan");
user.setGender(1);
user.setBirthday(new Date());
//保存user对象到数据库中
session.save(user);
//事务提交
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
HibernateUtil.closeResource(session);
}
}
}
数据库结果与之前一致:
hibernate的对象的三种状态
瞬时对象(TransientObjects):
刚new出来的对象, 在数据库中没有相应的记录, 也没有被session管理起来的对象
持久化对象(PersistentObjects):
在数据库中有相应的记录并且被session管理来的对象
脱管对象(DetachObjects):
在数据库中有相应的记录, 但没有被session管理起来的对象
这三种状态可以相互转换
当瞬时对象执行save()或者update()时会转换为持久化对象
当执行get()或load()或iterator()时从数据库中查询上来的对象就是持久化对象, 当持久化对象执行delete()时则转换为瞬时对象
当持久化对象执行evict()或close()或clear()时则转换为脱管对象
当脱管对象执行save()或update()时则转换为持久化对象
当脱管对象执行delete()时则转换为瞬时对象
由于其中的某些转换较为简单, 我只贴出一些我认为需要记忆的点
脱管对象转换为持久化对象, 一旦成为脱管对象了, 那么久意味着该对象只存在于数据库中, 此时session已经关闭了, 要想重新转换为持久化对象, 则必须新创建出一个session, 请看测试代码:
package com.rl.hiber.test;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.rl.hiber.model.User;
import com.rl.hiber.utils.HibernateUtil;
public class TestHibernate {
@Test
public void test3() {
Session session = HibernateUtil.getSessoion();
Transaction tx = session.beginTransaction();
User user = new User();
try {
user.setUname("张三");
user.setBirthday(new Date());
user.setGender(1);
session.save(user);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
//关闭session, 此时将对象user变成脱管对象
HibernateUtil.closeSession(session);
}
//重新创建一个session
Session session2 = HibernateUtil.getSessoion();
Transaction tx2 = session2.beginTransaction();
try {
user.setUname("李四");
session2.update(user);
tx2.commit();
} catch (Exception e) {
e.printStackTrace();
tx2.rollback();
}finally {
//关闭session2
HibernateUtil.closeResource(session2);
}
}
}
此时就将user对象转成了持久化对象(既被session管理, 又存在于数据库中)
通过查询获得持久化对象, 请看测试代码:
package com.rl.hiber.test;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.rl.hiber.model.User;
import com.rl.hiber.utils.HibernateUtil;
public class TestHibernate {
@Test
public void test2() {
Session session = HibernateUtil.getSessoion();
try {
User user = (User) session.get(User.class, 1);
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}finally {
HibernateUtil.closeResource(session);
}
}
}
tip: 查询并不需要开事务
这里先贴上load()的查询, 后续会讲解它们的区别(与延迟加载有关)
测试代码:
package com.rl.hiber.test;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.rl.hiber.model.User;
import com.rl.hiber.utils.HibernateUtil;
public class TestHibernate {
@Test
public void test4() {
Session session = HibernateUtil.getSessoion();
try {
User user = (User) session.load(User.class, 1);
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}finally {
HibernateUtil.closeResource(session);
}
}
}
get()和load()方法查询出来的对象都是持久化对象