Hibernate 事务管理 多表操作

    技术2022-07-14  102

    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(); } }

    Processed: 0.009, SQL: 9