Hibernate事务管理:
我们在真正进行事务管理的时候,需要考虑事务的应用场景,也就是说我们的事务控制不应该是在DAO层实现的,应该在Service层实现的,并且在Service中调用多个DAO实现一个业务逻辑的操作。其实最主要的是如何保证在Service中开启事务时使用的Session对象和DAO中多个操作使用的是同一个Session对象。可以有两种方法实现:
- 在业务层获取到Session,并将Session作为参数传递给DAO
- 使用ThreadLocal将业务层获取的Session绑定到当前线程中,然后在DAO中获取Session时,都从当前线程中获取。(这个操作Hibernate在内部已经帮我们做好了。我们可以通过sessionFactory.getCurrentSession()来获取与本地线程绑定的session对象。不过需要事先在核心配置文件中进行配置,否则会报异常。)
具体配置如下:
<property name="hibernate.current_session_context_class">thread</property>
配置好之后在关闭Session时就不需要我们手动关闭了。当线程他会自动关闭。如果加上手动关闭会报异常: Session was already closed
Hibernate中多表操作:
首先说表与表的三种关系:
- 一对一的关系:A表的一条记录对应B表的一条记录。B表中的一条记录也只对应A表中的一条记录(建表原则:可以让一方的主键对应另一方的主键)
- 一对多关系:A表的一条记录对应B表的多条记录。B表中的一条记录对应A表中的一条记录(建表原则:在多的一方创建外键指向一的一方的主键)
- 多对多关系:A表中的一条记录对应B表中的多条记录。B表中的一条记录也可以对应A表中的多条记录。(建表原则:创建一个中间表,中间表至少两个字段作为外键分别指向双方主键)
Hibernate中的一对多操作
示例:一用户角色只能在一个地区,但是一个地区可以有很多用户。
创建两个持久化类(省略一堆get和set):
public class NativePlace {
private Integer id;
private String nativePlace;
//一个地区有多个用户
private Set<User> userSet = new HashSet<User>();
}
public class User {
private Integer id;
private String userName;
private String password;
private String email;
private Double money;
//一个用户对应一个地区
private NativePlace nativePlace;
}
配置映射文件NativePlace.hbm.xml:
<?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.itcast.entity.NativePlace" table="t_nativer">
<id name="id" column="id">
<!--主键生成策略-->
<generator class="native"></generator>
</id>
<property name="nativePlace" column="native_place"></property>
<!-- (NativePlace中用的集合是set)set标签name属性值:多的一方的集合的属性名称 -->
<set name="userSet">
<!-- 一对多建表,有外键
hibernate机制:在一和多的那一方都配置外键
column属性值:外键名称
-->
<key column="jid"></key>
<!-- 此为一的一方 映射 多的一方的全类名 -->
<one-to-many class="cn.itcast.entity.User"></one-to-many>
</set>
</class>
</hibernate-mapping>
User.hbm.xml(除去相关的成员字段映射配置只需加上一条)
<!--
name属性:在User类中地区用nativePalce属性表示
-->
<many-to-one name="nativePlace" class="cn.itcast.entity.NativePlace" column="jid"></many-to-one>
核心配置文件中引入映射关系:
<!-- 引入映射配置文件 -->
<mapping resource="cn/itcast/entity/User.hbm.xml" />
<mapping resource="cn/itcast/entity/NativePlace.hbm.xml" />
一对多级联操作:
- 级联保存:添加一个地区,为此地区添加多个用户。
- 级联删除:删除一个地区,删除该地区的所有用户。
级联保存测试:
public class HibernateDemo04 {
public static void main(String[] args) {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
//创建新的地区
NativePlace nativePlace = new NativePlace();
nativePlace.setNativePlace("陕西省");
//创建多个用户
User user1 = new User("杨过", "121", "121@xx.com", 200.0);
User user2 = new User("小龙女", "121", "121@xx.com", 200.0);
//为用户设置地区
user1.setNativePlace(nativePlace);
user2.setNativePlace(nativePlace);
//将用户添加进集合
nativePlace.addUser(user1);
nativePlace.addUser(user2);
//保存到数据库
session.save(nativePlace);
session.save(user1);
session.save(user2);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
}
}
}
结果如下:
上述代码中是将双方都保存了。还可以只保存一方。那就需要先确定主控方。比如现在的主控方是用户,所以只需在
用户的映射文件中进行配置,如下:(增加了cascade属性)
<many-to-one name="nativePlace" class="cn.itcast.entity.NativePlace" column="jid" cascade="save-update"></many-to-one>
测试一下只保存一方是否可以级联到另一方(只需要将上述代码中业务内容修改一下即可):
NativePlace nativePlace = new NativePlace();
nativePlace.setNativePlace("广东省");
User user = new User("郭靖", "121", "121@xx.com", 200.0);
user.setNativePlace(nativePlace);
nativePlace.addUser(user);
//现在只需要保存主控方即可。即用户。级联是双向的。此处保存用户的同时级联地区。
session.save(user);
结果:
如果想保存的那一方是地区,则在NativePlace.hbm.xml中的set标签上添加该属性即可。
级联删除:
在NativePlace.hbm.xml映射配置文件中为cascade属性添加值delete。如下:
<set name="userSet" cascade="delete">
<key column="jid"></key>
<one-to-many class="cn.itcast.entity.User"></one-to-many>
</set>
public static void main(String[] args) {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
//获取地区信息
NativePlace nativePlace = session.get(NativePlace.class, 2);
//删除该地区信息的同时会级联到用户
session.delete(nativePlace);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
}
}
一对多修改操作:
public static void main(String[] args) {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
//获取用户
User user = session.get(User.class, 2);
//获取地区信息
NativePlace nativePlace = session.get(NativePlace.class, 2);
//修改该用户的地区并保存。
user.setNativePlace(nativePlace);
session.save(user);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
session.close();
}
}