1、持久化类和一级缓存
持久化类:JavaBean+映射的配置文件
持久化对象的三种状态
瞬时态
持久态
脱管态
Session的一级缓存,快照机制
主键的生成策略
常用uuid native
2、管理事务
设置隔离级别
丢失更新的问题,乐观锁:添加属性version,配置<version name="version">
绑定本地的session,事务需要在service层开启,dao层需要使用session对象
3、查询的接口
Query接口:HQL的查询
Criteria接口:QBC查询(按条件进行查询)
关联关系映射一对多映射
1、一对多的设计
2、导入SQL的建表语句
创建数据库
导入SQL脚本
3、编写客户和联系人的JavaBean程序(一对多的编写规则)
级联保存
1、如果代码只插入其中的一方的数据
如果只保存其中的一方的数据,那么程序会抛出异常
如果想完成只保存一方的数据,并且把相关联的数据都保存到数据库中,那么需要配置级联
级联保存是方向性的
2、级联保存的效果
级联保存:保存一方的同时可以把关联的对象也保存到数据库中
使用cascade="save-update"
级联删除
1、含有外键的删除客户功能,那么SQL语句会报错
delete from customers where cid =1;
2、如果使用Hibernate框架直接删除客户的时候 发现可删除
3、上述的删除是普通的删除,也可以使用级联删除,级联删除有方向性
<many-to-one cascade="delete"/> 一般都是假删除就加个字段置1或0表示已删除
cascade的取值和孤儿删除
1、取值
none 不使用级联
save-update 级联保存或更新
delete 级联删除
delete-orphan 孤儿删除(只能应用在一对多关系)
all 除了delete-orphan的所有情况(包含save-update delete)
all-delete-orphan 包含了delete-orphan的所有情况(包含save-update delete delete-orphan)
2、孤儿删除(孤子删除)只有在一对多的环境下才有孤儿删除
在一对多的关系下,可以将一的一方认为是父方,将多的一方认为是子方,孤儿删除:在解除了父子关系的时候,将子方记录就直接删除
<many-to-one cascade="delete-orphan"/>
某一方放弃外键的维护,为多对多作准备
1、双方都维护外键的时候,会产生多于的SQL语句
想修改客户和联系人的关系,进行双向关联,双方都会维护外键,会产生多余的SQL语句
产生的原因:session的一级缓存中的快照机制,会让双方都更新数据库,产生了多余的SQL语句
2、如果不想产生多余的SQL语句,那么需要一方来放弃外键的维护
在<set>标签上配置一个inverse="true",true:放弃,false:不放弃 默认false
<inverse="true">
cascade和inverse的区别
1、cascade用来级联操作(保存或者修改和删除)
多方 save-update
2、inverse用来维护外键的
一方放弃维护
级联保存
<set cascade="save-update">
级联删除(在多对多很少使用)
级联删除
/**
* 测试一对多
* @author Administrator
*
*/
public class Demo1 {
/**
* 双向关联的方式,保存数据
*/
@Test
public void run1() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//保存客户和联系人的数据
Customer c1 = new Customer();
c1.setCust_name("小明");
//创建2个联系人
Linkman l1 = new Linkman();
l1.setLkm_name("小弟");
Linkman l2 = new Linkman();
l2.setLkm_name("大哥");
//双向关联
c1.getLinkmans().add(l1);
c1.getLinkmans().add(l2);
l1.setCustomer(c1);
l2.setCustomer(c1);
//保存数据
session.save(c1);
session.save(l1);
session.save(l2);
tr.commit();
}
/**
* 单向的关联,如果不配置级联保存,程序出现异常
*/
@Test
public void run2() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//保存客户和联系人的数据
Customer c1 = new Customer();
c1.setCust_name("小明");
//创建2个联系人
Linkman l1 = new Linkman();
l1.setLkm_name("小弟");
Linkman l2 = new Linkman();
l2.setLkm_name("大哥");
//单向关联
c1.getLinkmans().add(l1);
c1.getLinkmans().add(l2);
//保存数据
session.save(c1);
tr.commit();
}
/**
* 级联保存 要去掉原来的表因为修改了表结构
* 保存客户,级联联系人
*/
@Test
public void run3() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//保存客户和联系人的数据
Customer c1 = new Customer();
c1.setCust_name("小明");
//创建2个联系人
Linkman l1 = new Linkman();
l1.setLkm_name("小弟");
Linkman l2 = new Linkman();
l2.setLkm_name("大哥");
//单向关联
c1.getLinkmans().add(l1);
c1.getLinkmans().add(l2);
//保存数据
session.save(c1);
tr.commit();
}
/**
* 级联保存:保存联系人,保存客户
*/
@Test
public void run4() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//保存客户和联系人的数据
Customer c1 = new Customer();
c1.setCust_name("小明");
//创建2个联系人
Linkman l1 = new Linkman();
l1.setLkm_name("小弟");
Linkman l2 = new Linkman();
l2.setLkm_name("大哥");
//使用联系人关联客户
l1.setCustomer(c1);
l2.setCustomer(c1);
//保存
session.save(l1);
session.save(l2);
//没有保存l2
tr.commit();
}
@Test
public void run5() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//保存客户和联系人的数据
Customer c1 = new Customer();
c1.setCust_name("小明");
//创建2个联系人
Linkman l1 = new Linkman();
l1.setLkm_name("小弟");
Linkman l2 = new Linkman();
l2.setLkm_name("大哥");
//使用联系人关联客户
l1.setCustomer(c1);
c1.getLinkmans().add(l2);
//保存
session.save(l1);
//没有保存l2
tr.commit();
}
/**
* 删除客户,客户有2个联系人
* 先把 lkm_cust_id外键置null
*/
@Test
public void run6() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//先查询1号客户
Customer c1 = session.get(Customer.class, 1L);
session.delete(c1);
tr.commit();
}
/**
* 级联删除 删除客户,级联删除客户下的联系人
*/
@Test
public void run7() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//先查询1号客户
Customer c1 = session.get(Customer.class, 1L);
session.delete(c1);
tr.commit();
}
/**
* 删除联系人,级联删除客户
*/
@Test
public void run8() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//先查询3号联系人
Linkman l1 = session.get(Linkman.class, 3L);
session.delete(l1);
tr.commit();
}
/**
* 测试级联删除
*/
@Test
public void run9() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//先查询3号联系人
Linkman l1 = session.get(Linkman.class, 3L);
session.delete(l1);
tr.commit();
}
/**
* 解除关系:从集合中删除联系人
*/
@Test
public void run10() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//先获取到客户
Customer c1 = session.get(Customer.class, 1L);
Linkman l1 = session.get(Linkman.class, 1L);
//解除
c1.getLinkmans().remove(l1);
tr.commit();
}
/**
* 放弃外键的维护
* 让小弟联系人属于小风
*/
@Test
public void run11() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//先获取到客户
Customer c2 = session.get(Customer.class, 2L);
Linkman l1 = session.get(Linkman.class, 1L);
//做双向关联
c2.getLinkmans().add(l1);
l1.setCustomer(c2);
//不用修改
tr.commit();
}
/**
* cascade和inverse的区别
*/
@Test
public void run12() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//保存客户和联系人的数据
Customer c1 = new Customer();
c1.setCust_name("小明");
//创建2个联系人
Linkman l1 = new Linkman();
l1.setLkm_name("小弟");
Linkman l2 = new Linkman();
l2.setLkm_name("大哥");
//单向关联
l1.setCustomer(c1);
l2.setCustomer(c1);
//保存数据
session.save(l1);
session.save(l1);
tr.commit();
}
}
public class Demo2 {
@Test
public void run1() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//模拟多对多,双向关联
User u1 = new User();
u1.setUsername("zs");
User u2 = new User();
u2.setUsername("ls");
//创建角色
Role r1 = new Role();
r1.setRname("小弟");
Role r2 = new Role();
r2.setRname("大哥");
//关联
u1.getRoles().add(r1);
u1.getRoles().add(r2);
r1.getUsers().add(u1);
r2.getUsers().add(u1);
u2.getRoles().add(r1);
r1.getUsers().add(u2);
session.save(u1);
session.save(u2);
session.save(r1);
session.save(r2);
tr.commit();
}
@Test
public void run2() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//模拟多对多,双向关联
User u1 = new User();
u1.setUsername("zs");
User u2 = new User();
u2.setUsername("ls");
//创建角色
Role r1 = new Role();
r1.setRname("小弟");
Role r2 = new Role();
r2.setRname("大哥");
u1.getRoles().add(r1);
u1.getRoles().add(r2);
u2.getRoles().add(r1);
//保存数据
session.save(u1);
session.save(u2);
tr.commit();
}
/**
* 张三用户,2个角色,大哥和小弟
* 让张三没有演员角色
*/
@Test
public void run3() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//查询张三用户
User u1 = session.get(User.class, 1L);
//查询角色
Role r2 = session.get(Role.class,2L);
u1.getRoles().remove(r2);
tr.commit();
}
}
Dao.Customer
public class CustomerDao {
/**
* 保存客户
*/
public void save(Customer c) {
//先获取session
Session session = HibernateUtils.getSession();
//开启事务
Transaction tr = session.beginTransaction();
//保存用户
session.save(c);
//提交事务
tr.commit();
//关闭资源
session.close();
}
/**
* 查询所有的客户
*/
public List<Customer> findAll(){
//QBC查询
Session session = HibernateUtils.getSession();
Transaction tr = session.beginTransaction();
//查询
Criteria criteria = session.createCriteria(Customer.class);
//查询
List<Customer> list = criteria.list();
tr.commit();
session.close();
return list;
}
/**
* 带查询条件的查询所有的客户
*/
public List<Customer> findAll(String custName){
//QBC查询
Session session = HibernateUtils.getSession();
Transaction tr = session.beginTransaction();
//查询
Criteria criteria = session.createCriteria(Customer.class);
//添加查询的条件
if(custName != null && !custName.trim().isEmpty()) {
//添加查询条件
criteria.add(Restrictions.like("cust_name", "%"+custName+"%"));
}
//查询
List<Customer> list = criteria.list();
tr.commit();
session.close();
return list;
}
/**
* 通过主键查询客户
* @param cust_id
* @return
*/
public Customer findById(Long cust_id) {
//使用session
Session session = HibernateUtils.getCurrentSession();
//查询
return session.get(Customer.class, cust_id);
}
}
Dao.Linkman
public class LinkmanDao {
/**
* 保存联系人
* @param man
*/
public void save(Linkman man) {
Session session = HibernateUtils.getCurrentSession();
System.out.println(man.toString());
session.save(man);
}
}
Domain.Linkman
public class Linkman {
/**
`lkm_id` BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
`lkm_name` VARCHAR(16) DEFAULT NULL COMMENT '联系人姓名',
`lkm_cust_id` BIGINT(32) NOT 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 '联系人备注',
*/
private Long lkm_id;
private String lkm_name;
private String lkm_cust_id;
private String lkm_gender;
private String lkm_phone;
private String lkm_mobile;
private String lkm_email;
private String lkm_qq;
private String lkm_position;
private String lkm_memo;
系统角色
/**
* 系统角色
* @author Administrator
*
*/
public class Role {
private Long rid;
private String rname;
private Set<User> users = new HashSet<User>();
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
/**
* 系统角色
* @author Administrator
*
*/
public class User {
private Long uid;
private String username;
private String password;
//编写的都是集合
private Set<Role> roles = new HashSet<Role>();
Customer.hbm.xml
<!-- 配置一方 -->
<!--
set标签name属性,表示集合的名称
一方对应的人多 每个都维护一遍还是让多方维护比较省力
-->
<set name="linkmans" inverse="true">
<!-- 需要出现子标签 -->
<!-- 外键的字段 -->
<key column="lkm_cust_id"></key>
<one-to-many class="my.domain.Linkman"/>
</set>
Linkman.hbm.xml
<!-- 先配置多方
name 当前javabean中的属性
class 属性的全路径
column 外键的字段
-->
<many-to-one name="Customer" class="my.domain.Customer" column="lkm_cust_id" cascade="save-update"/>
role.hbm.xml
<!-- 配置一方 -->
<!--
set标签name属性,表示集合的名称
一方对应的人多 每个都维护一遍还是让多方维护比较省力
-->
<!-- 多对多必须有一方放弃外键的维护 -->
<set name="users" table="sys_user_role" inverse="true">
<key column="rid"/>
<many-to-many class="my.domain.User" column="uid"/>
</set>
User.hbm.xml
<!-- 配置多对多
name 集合的名称
table 中间表的名称
-->
<set name="roles" table="sys_user_role" cascade="save-update">
<!-- 当前对象在中间表的外键名称 -->
<key column="uid"></key>
<!--
class 集合中存入对象,对象的全路径
column 集合中对象在中间表的外键名称
-->
<many-to-many class="my.domain.Role" column="rid"/>
</set>
LinkmanService
public class LinkmanService {
/**
* 编写业务,保存联系人
* 先把客户查询出来,设置到联系人中,再保存联系人
* @param man
* @param cust_id
*/
public void save(Linkman man, Long cust_id) {
//获取session
Session session = HibernateUtils.getCurrentSession();
//开启事务
Transaction tr = session.beginTransaction();
try {
//编写代码
//先查客户
Customer c = new CustomerDao().findById(cust_id);
//设置
man.setCustomer(c);
//保存联系人
new LinkmanDao().save(man);
tr.commit();
} catch(Exception e) {
tr.rollback();
e.printStackTrace();
}
}
}
Servlet.initAdd
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//查询所有的客户
List<Customer> list = new CustomerService().findAll();
//保存request
request.setAttribute("list", list);
request.getRequestDispatcher("/jsp/linkman/add.jsp").forward(request, response);
}
ServletAddLinkman
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//先解决中文乱码
request.setCharacterEncoding("utf-8");
//接受数据
Map<String,String[]> map = request.getParameterMap();
//先把客户的id获取到
String scust_id = map.get("cust_id")[0];
//转换
Long cust_id = Long.parseLong(scust_id);
//封装数据
Linkman man = new Linkman();
try {
//有对应的属性就封装上,没有就null
BeanUtils.populate(man, map);
//调用业务层,保存联系人
new LinkmanService().save(man,cust_id);
System.out.println(man);
} catch (Exception e) {
e.printStackTrace();
}
}