项目中框架的体系结构
ORM框架
对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping)
对象和表字段进行对应
是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
Object:对象,java对象,此处特指JavaBean,Model
Relational:关系,二维表,数据库中的表。
Mapping:映射
什么是hibernate
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装
DBUtils也是对JDBC的封装
它将POJO与数据库表建立映射关系,是一个全自动的orm框架
POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans
hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库
Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用
Hibernate是一个数据持久化层的ORM框架,它的主要功能就是把对象映射到表中,操作API,只需要将一个对象存储到数据库,不需要写sql语句
Hibernate提供了对关系型数据库增删改成操作
主流的ORM框架
JPA Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系(只有接口规范)
Hibernate 最流行ORM框架,通过对象-关系映射配置,可以完全脱离底层SQL
MyBatis 本是apache的一个开源项目 iBatis,支持普通 SQL查询,存储过程和高级映射的优秀持久层框架
Apache DBUtils 、Spring JDBCTemplate
Hibernate的优点
Hibernate对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码
Hibernate是一个基于jdbc的主流持久化框架,是一个优秀的orm实现,它很大程度的简化了dao层编码工作 session.save(User);
Hibernate使用java的反射机制
Hibernate的性能非常好,因为它是一个轻量级框架。映射的灵活性很出色。它支持很多关系型数据库,有一对一到多对多的各种复杂关系映射
Hibernate的使用步骤
下载hibernate 的jar包,并导入到项目中(http://hibernate.org/orm/)
创建数据库和表
配置核心配置文件hibernate.cfg.xml【这个文件有连接数据库的配置】
编写映射文件hibernate mapping(*.hbm.xml),【声明对象如何关联数据库表字段】
调用hibernate的api
入门案例
创建一个项目,引入jar包
创建表
CREATE TABLE `cst_customer` (
`cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
`cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
`cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
`cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
`cust_level` varchar(32) 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=1 DEFAULT CHARSET=utf8;
创建实体类
创建映射
映射需要通过XML的配置文件来完成,这个配置文件可以任意命名。尽量统一命名规范(类名.hbm.xml)
创建一个Hibernate的核心配置文件
Hibernate的核心配置文件的名称:hibernate.cfg.xml
编写测试代码
XML提示的配置
配置XML提示问题
映射的配置
【class标签的配置】
标签用来建立类与表的映射关系
属性:
name 类的全路径
table 表名(类名与表名一致,table可以省略)
catalog 数据库名
class标签的dynamic-insert="true" 是否动态生成插入语句
【id标签的配置】
标签用来建立类中的属性与表中的主键的对应关系
属性:
name 类中的属性名
column 表中的字段名(类中的属性名和表中的字段名如果一致,column可以省略)
length 长度
type 类型
【property标签的配置】
属性:
name 类中的属性名
column 表中的字段名(类中的属性名和表中的字段名如果一致,column可以省略)
length 长度
type 类型
not-null 设置非空
unique 设置唯一
Hibernate的核心配置方式
一种方式:属性文件的方式
hibernate.properties
hibernate.connection.driver_class=com.mysql.jdbc.Driver
…
hibernate.show_sql=true
属性文件的方式不能引入映射文件(手动编写代码加载映射文件)
二种方式:XML文件的方式
hibernate.cfg.xml
核心的配置
必须的配置
连接数据库的基本的参数
驱动类 hibernate.connection.driver_class
url路径 hibernate.connection.url
用户名 hibernate.connection.username
密码 hibernate.connection.password
可选的配置
显示SQL hibernate.show_sq
格式化SQL hibernate.format_sql
自动建表 hibernate.hbm2ddl.auto
none 不使用hibernate的自动建表
create 如果数据库中已经有表,删除原有表,重新创建,如果没有表,新建表。(测试)
create-drop 如果数据库中已经有表,删除原有表,然后创建执行操作,删除这个表。 如果没有表,新建一个, 使用完了删除该表。(测试)
update 如果数据库中有表,使用原有表,如果没有表,创建新表(更新表结构)
validate :如果没有表,不会创建表。只会使用数据库中原有的表。(校验映射和表结构)。
映射文件的引入
<mapping resource="cn/zjut/hibernate/domain/Customer.hbm.xml" />
Hibernate的API
Configuration Hibernate的配置对象
作用:
加载核心配置文件
hibernate.properties
Configuration cfg = new Configuration();
hibernate.cfg.xml
Configuration cfg = new Configuration().configure();
加载映射文件
// 手动加载映射
configuration.addResource("cn/zjut/hibernate/domain/Customer.hbm.xml")
SessionFactory Session工厂
SessionFactory内部维护了Hibernate的连接池和Hibernate的二级缓存。是线程安全的对象。一个项目创建一个对象即可。
配置连接池
<property name="connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
<!--在连接池中可用的数据库连接的最少数目 -->
<property name="c3p0.min_size">5</property>
<!--在连接池中所有数据库连接的最大数目 -->
<property name="c3p0.max_size">20</property>
<!--设定数据库连接的过期时间,以秒为单位,
如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
<property name="c3p0.timeout">120</property>
<!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->
<property name="c3p0.idle_test_period">3000</property>
抽取工具类
Session 类似Connection对象是连接对象
Session代表的是Hibernate与数据库的链接对象。不是线程安全的。与数据库交互桥梁。
Session中的API
保存方法:
Serializable save(Object obj);
查询方法:
T get(Class c,Serializable id);
T load(Class c,Serializable id);
get方法和load方法的区别?
load执行原理图
修改方法
void update(Object obj);
删除方法
void delete(Object obj);
保存或更新
void saveOrUpdate(Object obj)
查询所有
Transaction 事务对象
commit();
rollback();
持久化类
Hibernate是持久层的ORM映射框架,专注于数据持久化工作。所谓持久化,就是将内存中的数据永久存储到关系型数据库中。所谓持久化类就是一个Java类与数据库表建立映射关系,那么这个类称为持久化类。
持久化类编写规则
持久化类需要提供无参构造方法。Hibernate底层需要使用反射生成类的实例对象。
持久化类的属性需要私有,对私有属性提供get和set方法。在Hibernate底层会将查询到的数据进行封装。
持久化类属性尽量使用包装类类型。包装类和基本数据类型默认值不同,包装类类型语义描述更清晰而基本数据类型不容易描述。
持久化类要有一个唯一标识OID与表的主键对应。Hibernate需要通过这个唯一标识OID区分内存中是否是同一个持久化类。在关系型数据库的表中是通过主键区分是否是同一条记录。Hibernate是不允许在内存中出现两个OID相同的持久化对象。
持久化类尽量不要使用final进行修饰。Hibernate有延迟加载机制,这个机制会产生代理对象,Hibernate产生代理对象是使用字节码增强技术完成的,其实是产生当前类的一个子类对象实现的。如果使用final修饰持久化类,那么不能产生子类,那么Hibernate延迟加载机制就会失效
主键生成策略
主键具备:不为空/不能重复/不能改变
自然主键:把具有业务含义的字段作为主键,称之为自然主键。
代理主键:把不具有业务含义的字段作为主键,称之为代理主键。
持久化对象三种状态
瞬时态(transient)
瞬时态也称为临时态或者自由态,瞬时态的实例是由new命令创建、开辟内存空间的对象,不存在持久化标识OID(相当于主键值),尚未与Hibernate Session关联,在数据库中也没有记录,瞬时状态的对象在内存中是孤立的,与数据库中的数据无任何关联,仅是一个信息携带的载体。
持久态(persistent)
持久化对象存在持久化标识OID,加入到Session缓存中,并且相关联的Session没有关闭,数据库中有对应的记录,每条记录只对应唯一的持久化对象,持久态对象是在事务还未提交前变成持久态的。
脱管态(detached)
脱管态也称为离线态或者游离态,当某个持久化状态的实例与Session的关联被关闭就变成脱管态,脱管态对象存在持久化标识OID,并且仍然与数据库中的数据存在关联,只是失去了与当前Session的关联,脱管状态对象发生改变时Hibernate不能检测到。
三种状态互相转化
Hibernate持久化对象能够自动更新数据库
Hibernate一级缓存
Hibernate的一级缓存就是指Session缓存,Session缓存是一块内存空间,用来存放相互管理的Java对象,在使用Hibernate查询对象的时候,首先使用对象属性的OID值在Hibernate的一级缓存中进行查找,如果匹配OID值的对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库;如果没有找到相同OID值对象,就会去数据库中查找相应数据。当从数据库查询到所需数据时,该信息也会放到一级缓存中。Hibernate的一级缓存的作用就是减少对数据库的访问次数。
在Session接口实现中包含一系列Java集合,这些集合集合构成Session缓存。只要session实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。
测试一级缓存
移除缓存
一级缓存内部结构(快照区)
Hibernate向一级缓存存放数据时,同时复制一份数据到Hibernate快照中,当使用commit()提交事务时,同时会清理Session的一级缓存,这时会清理Session的一级缓存,这时会使用OID判断一级缓存中的对象和快照中对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将缓存内容同步到数据库,并更新数据库;如果一致,则不执行update语句。Hibernate快照的作用就是确保一级缓存中的数据和数据库中的数据一致。
事务
在数据库操作中,一项事务(Transaction)是由一条或多条操作数据库的SQL语句组成的一个不可分割的工作单元。当事务中的所有操作都正常完成时,整个事务才能被提交到数据库中,如果有一项操作没有完成,则整个事务会被回滚。总的来说:逻辑上的一组操作,组成这组操作的各个单元,要么一起成功,要么一起失败。
事务的四个特性
事务由很严格的定义,需要同时满足四个特性,即原子性、一致性、隔离性、持久性。这四个特性通常称之为ACID特性。
原子性(Atomic):表示事务中所做的操作捆绑成一个不可分割的单元,即对事务所进行的数据修改等操作,要么全部执行,要么全都不执行。
一致性(Consistency):表示事务完成时,必须使所有的数据都保持一致状态。
隔离性(Isolation):指一个事务的执行不能被其它事务干扰。即一个事务内部操作及使用的数据对并发的其它事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(Durability):持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。提交后的其他操作或故障不会对其有任何影响。
事务的并发问题
脏读:一个事务读取到另一个事务未提交的数据。
不可重复读:一个事务读到另一个事务已经提交的update的数据,导致在同一个事务中的多次查询结果不一致。
虚读/幻读:一个事务读到了另一个事务已经提交到的insert的数据,导致在同一个事务中的多次查询结果不一致。
事务隔离级别
读未提交(Read Uncommitted, 1级)
读已提交(Read Committed,2级)
可重复读(Repeatable Read,4级)
序列化/串行化(Serializable,8级)
事务隔离级别,是由数据库提供的,并不是所有数据库都支持四种隔离级别
MySQL:READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE
Oracle:READ_UNCOMMITTED、READ_COMMITTED、SERIALIZABLE
在使用数据库时候,隔离级别越高,安全性越高,性能越低
实际开发中,不选择最高或者最低隔离级别,选择READ_COMMITTED(Oracle默认)、REPEATABLE_READ(MySQL默认)
Hibernate中的事务管理
在真正进行事务管理的时候,需要考虑事务的应用场景,也就是事务控制不应该是在DAO层实现的,应该在Service层实现,并且在Service中调用多个DAO实现一个业务逻辑的操作。最主要是如何保证在Service中开启的事务时时使用的Session对象和DAO中多个操作使用是同一个Session对象。
两种办法可以实现
可以在业务层获取到Session,并将Session作为参数传递给DAO
可以使用ThreadLocal将业务层获取的Session绑定到当前线程中,然后在DAO中获取Session的时候,都从当前线程获取。
Hibernate的其他API
Query代表面向对象的一个Hibernate查询操作。在Hibernate中,通常使用session.createQuery()接受一个HQL语句,然后调用Query的list()或uniqueResult()执行查询。所谓HQL是Hibernate Query Language缩写,其语法很像SQL语法,但它是完全面向对象的。
Session session = HibernateUtil.openSession();
//查询所有记录
/*
Query query = session.createQuery("from Customer");
List<Customer> list = query.list();
System.out.println(list);
*/
//条件查询
/*
Query query = session.createQuery("from Customer where cust_name = ?");
query.setString(0,"张三");
//query.setParameter(0, "张三");
List<Customer> list = query.list();
System.out.println(list);
*/
//条件查询
/*
Query query = session.createQuery("from Customer where cust_name = :aaa and cust_source = :bbb");
query.setString("aaa","张三");
query.setString("bbb","旁门左道");
List<Customer> list = query.list();
System.out.println(list);
*/
//分页查询询
Query query = session.createQuery("from Customer");
query.setFirstResult(0);
query.setMaxResults(3);
List<Customer> list = query.list();
System.out.println(list);
session.close();
Query中除了使用list()方法查询全部数据外,还有其它一些常用方法
setter方法:Query接口中提供一系列setter方法用于设置查询语句中的参数,针对不同数据类型,需要不同的setter方法
iterator()方法:该方法用于查询语句,返回结果是一个Iterator对象,在读取时只能按照顺序方式读取,它仅把使用到的数据转换成Java实体对象。
uniqueResult()方法:该方法用于返回唯一结果,在确保只有一条记录查询时可以使用该方法。
setFirstResult()方法:该方法可以设置获取第一个记录的位置,也就是它表示从第几条记录开始查询,默认从0开始计算。
setMaxResult()方法:该方法用于设置结果集的最大记录数,通常与setFirstResult()方法结合使用,用于限制结果集的范围,以实现分页功能。
executeUpdate()方法:该方法是Hibernate3的新特性,它支持HQL语句的更新和删除操作。
Criteria
Criteria是一个完全面向对象,可扩展的条件查询API,通过它完全不需要考虑数据库底层如何实现,以及SQL语句如何编写,它是Hibernate框架的核心查询对象。Criteria查询,又称为QBC查询,它是Hibernate的另一种对象检索方式。
org.hibernate.criterion.Criterion是Hibernate提供的一个面向对象查询条件接口,一个单独的查询就是Criterion接口的一个实例,用于限制Criteria对象的查询,在Hibernate中Criterion对象的创建通常是通过Restrictions工厂类完成的,它提供了条件查询的方法。
Session session = HibernateUtil.openSession();
//查询所有记录
/*
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();
System.out.println(list);
*/
//条件查询
/*
Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.eq("cust_name","张三"));
List<Customer> list = criteria.list();
System.out.println(list);
*/
//条件查询
/*
Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.eq("cust_name","张三"));
criteria.add(Restrictions.eq("cust_source","旁门左道"));
List<Customer> list = criteria.list();
System.out.println(list);
*/
//分页查询询
Criteria criteria = session.createCriteria(Customer.class);
criteria.setFirstResult(3);
criteria.setMaxResults(3);
List<Customer> list = criteria.list();
System.out.println(list);
session.close();
在Criteria对象中,除了使用criteria.list()方法查询全部数据外,还有其它一些常用方法:如果只返回一个值,可以使用criteria的uniqueResult()方法
SQLQuery
SQLQuery这个接口用于接收一个sql语句进行查询,然后调用list()或者uniqueResult()方法进行查询。但是sql语句不会直接封装到实体对象中,需要手动写代码封装到实体中
Session session = HibernateUtil.openSession();
SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
List<Object[]> list = sqlQuery.list();
for (Object[] objects: list) {
System.out.println(Arrays.toString(objects));
}
session.close();
数据库表与表之间的关系
一对多关系
一个部门对应多个员工,一个员工只能属于某一个部门
一个客户对应多个联系人,一个联系人只能属于某一个客户
一对多的建表原则
多对多关系
一个学生可以选择多门课程,一门课程也可以被多个学生选择。
一个用户可以选择多个角色,一个角色也可以被多个用户选择。
多对多的建表原则
一对一关系
一对一的建表原则
Hibernate一对多的关系配置
创建一个项目,引入相应jar包
创建数据库和表
CREATE TABLE `cst_customer` (
`cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
`cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
`cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
`cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
`cust_level` varchar(32) 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=1 DEFAULT CHARSET=utf8;
CREATE TABLE `cst_linkman` (
`lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
`lkm_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名',
`lkm_cust_id` bigint(32) DEFAULT NULL COMMENT '客户id',
`lkm_gender` char(1) DEFAULT NULL COMMENT '联系人性别',
`lkm_phone` varchar(16) DEFAULT NULL COMMENT '联系人办公电话',
`lkm_mobile` varchar(16) DEFAULT NULL COMMENT '联系人手机',
`lkm_email` varchar(64) DEFAULT NULL COMMENT '联系人邮箱',
`lkm_qq` varchar(16) DEFAULT NULL COMMENT '联系人qq',
`lkm_position` varchar(16) DEFAULT NULL COMMENT '联系人职位',
`lkm_memo` varchar(512) DEFAULT NULL COMMENT '联系人备注',
PRIMARY KEY (`lkm_id`),
KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`),
CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
创建实体
一的一方的实体
多的一方的实体
创建映射文件
多的一方的映射的创建
<?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="cn.zjut.hibernate.domain.LinkMan" table="cst_linkman">
<id name="lkm_id" column="lkm_id">
<generator class="native"/>
</id>
<property name="lkm_name"/>
<property name="lkm_gender"/>
<property name="lkm_phone"/>
<property name="lkm_mobile"/>
<property name="lkm_email"/>
<property name="lkm_qq"/>
<property name="lkm_position"/>
<property name="lkm_memo"/>
<!--
配置多对一关系,放置的是一的一方对象
many-to-one标签
name 一的一方对
象属性名称
class 一的一方类的全路径
column 多的一方表的外键名称
-->
<many-to-one name="customer" class="cn.zjut.hibernate.domain.Customer" column="lkm_cust_id"/>
</class>
</hibernate-mapping>
一的一方的映射的创建
<?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="cn.zjut.hibernate.domain.Customer" table="cst_customer">
<id name="cust_id" column="cust_id" >
<generator class="native"/>
</id>
<property name="cust_name" column="cust_name" length="32" />
<property name="cust_source" column="cust_source" length="32"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
<!--
配置一对多关系,放置的是多的一方集合
set标签
name 多的一方对象集合属性名称
-->
<set name="linkMans">
<!--
key标签
column 多的一方表的外键名称
-->
<key column="lkm_cust_id"/>
<!--
one-to-many标签
class 多的一方类的全路径
-->
<one-to-many class="cn.zjut.hibernate.domain.LinkMan"/>
</set>
</class>
</hibernate-mapping>
创建核心配置文件
引入工具类
编写测试类
一对多关系只保存一边是否可以
一对多的级联操作
级联指的是,操作一个对象的时候,是否会同时操作其关联的对象。
级联是有方向性
操作一的一方的时候,是否操作到多的一方
操作多的一方的时候,是否操作到一的一方
保存客户级联联系人
Session session = HibernateUtil.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("张三");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("关门");
customer.getLinkMans().add(linkMan);
linkMan.setCustomer(customer);
session.save(customer);
transaction.commit();
session.close();
保存联系人级联客户
Session session = HibernateUtil.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("张三");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("关门");
customer.getLinkMans().add(linkMan);
linkMan.setCustomer(customer);
session.save(linkMan);
transaction.commit();
session.close();
测试对象的导航
Session session = HibernateUtil.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("张三");
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("关一");
LinkMan linkMan2 = new LinkMan();
linkMan2.setLkm_name("关二");
LinkMan linkMan3 = new LinkMan();
linkMan3.setLkm_name("关三");
linkMan1.setCustomer(customer);
customer.getLinkMans().add(linkMan2);
customer.getLinkMans().add(linkMan3);
//双方都设置cascade
//session.save(linkMan1);//4条insert语句
//session.save(customer);//3条insert语句
session.save(linkMan2);//1条insert语句
transaction.commit();
session.close();
级联删除
删除一边的时候,同时将另一方的数据也一并删除。
删除客户级联删除联系人
删除联系人级联删除客户(基本不用)
一对多设置了双向关联产生多余的SQL语句
解决多余的SQL语句
单向维护
使一方放弃外键维护权
一的一方放弃。在set上配置inverse=”true”
区分cascade和inverse
Hibernate多对多关系的配置
创建表
用户表
CREATE TABLE `sys_user` (
`user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`user_code` varchar(32) NOT NULL COMMENT '用户账号',
`user_name` varchar(64) NOT NULL COMMENT '用户名称',
`user_password` varchar(32) NOT NULL COMMENT '用户密码',
`user_state` char(1) NOT NULL COMMENT '1:正常,0:暂停',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
角色表
CREATE TABLE `sys_role` (
`role_id` bigint(32) NOT NULL AUTO_INCREMENT,
`role_name` varchar(32) NOT NULL COMMENT '角色名称',
`role_memo` varchar(128) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
中间表
CREATE TABLE `sys_user_role` (
`role_id` bigint(32) NOT NULL COMMENT '角色id',
`user_id` bigint(32) NOT NULL COMMENT '用户id',
PRIMARY KEY (`role_id`,`user_id`),
KEY `FK_user_role_user_id` (`user_id`),
CONSTRAINT `FK_user_role_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`role_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_user_role_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
创建实体
创建映射
用户的映射
<?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="cn.zjut.hibernate.domain.User" table="sys_user">
<id name="user_id" column="user_id">
<generator class="native"></generator>
</id>
<property name="user_code"/>
<property name="user_name"/>
<property name="user_password"/>
<property name="user_state"/>
<!--建立与角色的多对多关系-->
<!--
set标签
name 对方集合属性名称
table 多对多关系需要中间表,放的是中间表名称
-->
<set name="roles" table="sys_user_role">
<!--
key标签
column 当前对象对应中间表的外键名称
-->
<key column="user_id"/>
<!--
many-to-many标签
class 对方类的全路径
column 对方对象在中间表的外键名称
-->
<many-to-many class="cn.zjut.hibernate.domain.Role" column="role_id"/>
</set>
</class>
</hibernate-mapping>
角色的映射
<?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="cn.zjut.hibernate.domain.Role" table="sys_role">
<id name="role_id" column="role_id">
<generator class="native"/>
</id>
<property name="role_name"/>
<property name="role_memo"/>
<!--建立与用户的多对多关系-->
<!--
set标签
name 对方集合属性名称
table 多对多关系需要中间表,放的是中间表名称
-->
<set name="users" table="sys_user_role" inverse="true">
<!--
key标签
column 当前对象对应中间表的外键名称
-->
<key column="role_id"/>
<!--
many-to-many标签
class 对方类的全路径
column 对方对象在中间表的外键名称
-->
<many-to-many class="cn.zjut.hibernate.domain.User" column="user_id"/>
</set>
</class>
</hibernate-mapping>
编写测试代码
只保存一边是否可以
Session session = HibernateUtil.openSession();
Transaction transaction = session.beginTransaction();
User user = new User();
user.setUser_name("张三");
Role role = new Role();
role.setRole_name("研发");
user.getRoles().add(role);
role.getUsers().add(user);
//session.save(user);
session.save(role);
transaction.commit();
session.close();
多对多的级联保存或更新
保存用户级联保存角色
Session session = HibernateUtil.openSession();
Transaction transaction = session.beginTransaction();
User user = new User();
user.setUser_name("张三");
Role role = new Role();
role.setRole_name("研发");
user.getRoles().add(role);
role.getUsers().add(user);
session.save(user);
transaction.commit();
session.close();
保存角色级联保存用户
Session session = HibernateUtil.openSession();
Transaction transaction = session.beginTransaction();
User user = new User();
user.setUser_name("张三");
Role role = new Role();
role.setRole_name("研发");
user.getRoles().add(role);
role.getUsers().add(user);
session.save(role);
transaction.commit();
session.close();
多对多的级联删除(基本用不上)
删除用户级联删除角色
删除角色级联删除用户
多对多的其他的操作
给用户选择角色
给用户改选角色
给用户删除角色