- 浏览: 140292 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
aa87963014:
很好,但是update/insert 是否加锁 。加锁对sel ...
数据库锁 -
RobustTm:
我的这种做法也可以添加A和B
但是换成更新就有问题
hibernate入门(十一):级联操作inversin属性 -
RobustTm:
这位仁兄可以提供一对多双向关联完整的代码不?
我碰到了问题,采 ...
hibernate入门(十一):级联操作inversin属性 -
cfeers:
markxing 写道谢谢分享。。。
不客气,呵呵。
struts2.0 struts.xml配置文件详解 -
markxing:
谢谢分享。。。
struts2.0 struts.xml配置文件详解
1.事务引发的三层架构MVC讨论:
在前面的程序代码中多次用到了事务:
Transaction tx = s.beginTransaction();
对应的jdbc代码:connection. setAutoCommit(false);
.....
.....数据处理
.....
tx.commit();
对应的jdbc代码:connection.commit();
tx.rollback();
对应的jdbc代码:connection.rollback();
以上的三处事务相关的代码统称为“事务边界”。其实hibernate的事务本质是依赖jdbc的事务来实现,其实对于事务而言,它是应该由业务逻辑层来实现,但是事务所依赖的对象又出现在Model层,所以想严格按照MVC的原理来实现将相当难(在前面我们所写的代码中事务的处理是不符合mvc模式得),但是利用推出的EJB,SPRING这些框架将能达到此目的,下图展示了三层架构,与原始的MVC相比,多了一个持久层。
2.模拟session context:
>>步骤一,重写工具类,核心代码如下:
- package com.asm.hibernate.utils;
- public class HibernateUtilOSV {
- private static SessionFactory sf;
- private static ThreadLocal session = new ThreadLocal();
- private HibernateUtilOSV() {
- }
- public static Session getThreadLocalSession() {
- Session s = (Session) session.get();
- if (s == null) {
- s = getSession();
- session.set(s);
- }
- return s;
- }
- public static void closeSession() {
- Session s = (Session) session.get();
- if (s != null) {
- s.close();
- session.set(null);
- }
- }
- static {
- Configuration cf = new Configuration();
- cf.configure();
- sf = cf.buildSessionFactory();
- }
- public static SessionFactory getSessionFactory() {
- return sf;
- }
- public static Session getSession() {
- return sf.openSession();
- }
- }
package com.asm.hibernate.utils; public class HibernateUtilOSV { private static SessionFactory sf; private static ThreadLocal session = new ThreadLocal(); private HibernateUtilOSV() { } public static Session getThreadLocalSession() { Session s = (Session) session.get(); if (s == null) { s = getSession(); session.set(s); } return s; } public static void closeSession() { Session s = (Session) session.get(); if (s != null) { s.close(); session.set(null); } } static { Configuration cf = new Configuration(); cf.configure(); sf = cf.buildSessionFactory(); } public static SessionFactory getSessionFactory() { return sf; } public static Session getSession() { return sf.openSession(); } }
>>步骤二、导入servlet包,使用Filter. 内容如下:
- package com.asm.hibernate.osv;
- public class OpenSessionViewFilter implements Filter {
- public void destroy() {
- // TODO Auto-generated method stub
- }
- public void doFilter(ServletRequest arg0, ServletResponse arg1,
- FilterChain arg2) throws IOException, ServletException {
- Session s = null;
- Transaction tx = null;
- try {
- s = HibernateUtilOSV.getThreadLocalSession();
- tx = s.beginTransaction();
- arg2.doFilter(arg0, arg1);
- tx.commit();
- } catch (Exception e) {
- if (tx != null)
- tx.rollback();
- } finally {
- HibernateUtilOSV.closeSession();
- }
- }
- public void init(FilterConfig arg0) throws ServletException {
- // TODO Auto-generated method stub
- }
- }
package com.asm.hibernate.osv; public class OpenSessionViewFilter implements Filter { public void destroy() { // TODO Auto-generated method stub } public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { Session s = null; Transaction tx = null; try { s = HibernateUtilOSV.getThreadLocalSession(); tx = s.beginTransaction(); arg2.doFilter(arg0, arg1); tx.commit(); } catch (Exception e) { if (tx != null) tx.rollback(); } finally { HibernateUtilOSV.closeSession(); } } public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
>>步骤三、Userdao:
- package com.asm.hibernate.osv;
- public class UserDao {
- static void addUseDao(User user) {
- HibernateUtilOSV.getThreadLocalSession().save(user);
- }
- }
package com.asm.hibernate.osv; public class UserDao { static void addUseDao(User user) { HibernateUtilOSV.getThreadLocalSession().save(user); } }
原理流程分析:当有被Filter监测的请求到达此Filter时,Filter会利用工具类来获得一个Session,并用这个session打开事务,然后再把请求传给下一个Filter.当所有操作执行完成后再返回到这个Filter,如果没有任何异常便可以提交事务,否则回滚事务。这样便可以有效保证事务的完整性,而且有利于懒加载,因为在整个请求的过程中,Session一直未关闭,所以在filter不断向下传递的过程中可以放心的使用session来完成懒加载,这也是解决懒加载的一种方式。其实OpenSessionInView主要解决了两个问题:一是实现事务在逻辑层控制,二是利于懒加载的实现。下面再来看看工具类:此工具类主要完成了两个工作:一是生成一个线程级的Session,即是说在一个线程的事务开启到事务结束,一直用的是同一个Session,这样有利于保证事务的完整性,而工具类主要借助了ThradLocal来生成这个线程级的Session。 二是完成Session的关闭。
3.使用Hibernate自带的SessionContext
>>步骤一、在主配置文件中增加如下内容:
<property name="current_session_context_class">thread</property>以支持事务边界。 说明:它实质也是利用ThreadLocal来管理Session实现多个操作共享一个Session,避免反复获取Session,并控制事务边界。需要注意的是,当我们打开此功能后再通过SessionFactory.getCurrentSession()来获取一个Session,这个Session不能调用close方法,因为当我们提交事务或者回滚事务都会引起这个Session关闭,而通常的事务最会被提交或回滚,所以我们永远不要在这样的Session中调用close方法。同样的它的一个重要作用就是在生成页面时保持Session打开(即OpenSessionInView),因此为懒加载提供了方便。 除了配置为thread外还可以配置值为“jta” ,配置成jta后主要JTA事务管理器来管理事务,jta事务管理器主要用在有多个数据库的情况
>>步骤二、重写工具类:核心代码如下:
- package com.asm.hibernate.utils;
- public class HibernateUtilSelf {
- private static SessionFactory sf;
- private HibernateUtilSelf() {
- }
- public static Session getThreadLocalSession() {
- Session s = sf.getCurrentSession();
- if (s == null) {
- s = getSession();
- }
- return s;
- }
- static {
- Configuration cf = new Configuration();
- cf.configure();
- sf = cf.buildSessionFactory();
- }
- public static SessionFactory getSessionFactory() {
- return sf;
- }
- public static Session getSession() {
- return sf.openSession();
- }
- }
package com.asm.hibernate.utils; public class HibernateUtilSelf { private static SessionFactory sf; private HibernateUtilSelf() { } public static Session getThreadLocalSession() { Session s = sf.getCurrentSession(); if (s == null) { s = getSession(); } return s; } static { Configuration cf = new Configuration(); cf.configure(); sf = cf.buildSessionFactory(); } public static SessionFactory getSessionFactory() { return sf; } public static Session getSession() { return sf.openSession(); } }
>>编写测试类:
- package com.asm.hibernate.osv;
- public class UserTest {
- public static void main(String[] args) {
- User user = new User();
- user.setName("richie");
- user.setDate(new Date());
- addUser(user);
- }
- static void addUser(User user) {
- Session s = null;
- Transaction ts = null;
- try {
- s = HibernateUtilSelf.getThreadLocalSession();
- ts = s.beginTransaction();
- s.save(user);
- ts.commit();
- } catch (HibernateException e) {
- if (ts != null)
- ts.rollback();
- throw e;
- } finally {
- if (s != null)
- // s.close(); //注意这里不能使用close,并注意下面的打印结果
- System.out.println("s=" + s);
- }
- }
- }
package com.asm.hibernate.osv; public class UserTest { public static void main(String[] args) { User user = new User(); user.setName("richie"); user.setDate(new Date()); addUser(user); } static void addUser(User user) { Session s = null; Transaction ts = null; try { s = HibernateUtilSelf.getThreadLocalSession(); ts = s.beginTransaction(); s.save(user); ts.commit(); } catch (HibernateException e) { if (ts != null) ts.rollback(); throw e; } finally { if (s != null) // s.close(); //注意这里不能使用close,并注意下面的打印结果 System.out.println("s=" + s); } } }
执行后的结果为:s=SessionImpl(<closed>)
4.悲观锁:
悲观地认为每个事务在操纵数据时,肯定会有其它的事务同时访问该数据资源,当前事务为防止自身受到影响,先将相关数据资源锁定,直到事务结束后释放锁定。
实现方式一:利用LockMode实现数据锁;原理是使用带有LockMode参数的load方法来实现数据加锁,LockMode主要有以下几种锁定方式:
锁定方式 |
功能 |
LockMode.NONE |
Hibernate的默认值,首先到缓存中检索,检测不到时连数据库 |
LockMode.READ |
不管缓存,直接到数据库中加载。如果在实体配置文件中配置了版本元素,则比较缓存中的版本与数据库中的版本是否一致 |
LockMode.UPGRADE |
在READ的基础上,如果数据库支持悲观锁,则执行select...for update,否则执行变通的select语句。 |
UPGRADE_NOWAIT |
主要是针对Oracle数据库,在UPGRADE的基础上,如果执行select语句不能获得锁,则会抛出锁定异常 |
实现方式二、通过逻辑实现锁定数据;原理是在实体类的数据库表中设定一个boolean的字段,当这个字段为true,表示该数据正在被访问,此时记录被锁定。如果为false,则表示可以访问。过程:(1)当访问的数据为false时,表示可以访问,此时修改字段为true,以避免其它对象访问,操作完成后再设此字段为false,以让等待的对象访问 (2)当访问数据据为true,表示不可被访问。
5.乐观锁:
乐观地认为每个事务在操纵数据时,很少有或者不会其它事务同时访问数据资源,因而不会在数据库层锁定,而是通过逻辑来实现版本控制。
实现方式一:<version>方式:为了方便操作新建一个名为OptimizeLock的项目.
>>步骤一,拷贝以前的User类及相应的实体配置文件等相关文件。
>>步骤二,在User类中增加private int version;及相应的get/set方法。Version名字可以随意取。
>>步骤三、修改配置文件:增加<version name="version"></version>属性,并注意在<class>元素中使用optimistic-lock="version"属性,这也是官方推荐使用的属性值。但不能使用none,因为它不支持乐观锁,也可这样说,即使我们为乐观锁做好了一切准备,但我们不想在某个实体对象中使用时,只需要配置optimistic-lock为none即可。
>>步骤四、编写测试类
- package com.asm.hibernate.test;
- public class VersionUserTest {
- public static void main(String[] args) {
- addUser();
- update(1);
- }
- static void update(int id) {
- Session s1 = null;
- Session s2 = null;
- Transaction tx1 = null;
- Transaction tx2 = null;
- try {
- s1 = HibernateUtil.getSession();
- tx1 = s1.beginTransaction();
- User user1 = (User) s1.get(User.class, id);
- System.out.println(user1.getName());
- s2 = HibernateUtil.getSession();
- tx2 = s2.beginTransaction();
- User user2 = (User) s2.get(User.class, id);
- user1.setName("user1Name");
- user2.setName("user2Name");
- tx1.commit();
- tx2.commit();
- } catch (HibernateException e) {
- ....
- } finally {
- ....
- }
- }
- static void addUser() {
- ...主要作用是增加一条记录以实现操作。
- }
- }
package com.asm.hibernate.test; public class VersionUserTest { public static void main(String[] args) { addUser(); update(1); } static void update(int id) { Session s1 = null; Session s2 = null; Transaction tx1 = null; Transaction tx2 = null; try { s1 = HibernateUtil.getSession(); tx1 = s1.beginTransaction(); User user1 = (User) s1.get(User.class, id); System.out.println(user1.getName()); s2 = HibernateUtil.getSession(); tx2 = s2.beginTransaction(); User user2 = (User) s2.get(User.class, id); user1.setName("user1Name"); user2.setName("user2Name"); tx1.commit(); tx2.commit(); } catch (HibernateException e) { .... } finally { .... } } static void addUser() { ...主要作用是增加一条记录以实现操作。 } }
分析:在进行分析前,先提下笔者曾范的一个测试错误,由于是复制以前的代码,由于以前在User的配置文件中配置了二级缓存的“<cache usage="read-only"/>” ,这样执行时总是报“Can't write to a readonly object” 。由这点大家可以再细想下悲观锁的更多细节问题。下面来谈version,当我们向数据表中添加一个version字段,hibernate会控制此字段,当访问一条记录时,同时访问此记录的版本信息,如果对该记录做了修改,在提交事务时,hibernate会将访问时的版本信息与数据库中的版本信息进行对比,如果一致则提交修改并将原版本信息加1,否则撤销本次修改。 上面的两个session并分别有开启了两个事务,当提交第一个事务时,符合要求进行了提交。但我们再来提交第二个事务时,由于第一个事务修改了版本信息,尽管user1和user2最初获得的版本是一样得,但由于第一个事务提交修改了数据库中版本信息,所以第二个事务将不能被提交(如不能明白,请仔细阅读本段中的黑体字部份)。 请这样测试:执行完后(会报“Transaction not successfully started”异常)查数据表,然后再交换以上两个事务提交的顺序再执行,再查数据表。 另请不要深究异常处理。
实现方式二、<timestamp>
基本和方式一相同,只是在User类中增加一个Date类型的属性,同时在实体配置文件配置如下内容: <timestamp name="实体类的中Date类型的属性"></timestamp>
发表评论
-
hibernate.cfg.xml文件详解(annotation 配置)
2010-08-26 15:57 1561一、 环境搭建和基本映 ... -
hibernate.cfg.xml文件详解
2010-08-26 15:56 742<?xml version='1.0' encoding ... -
hiberante入门(十七):简要总结及源码文档
2010-08-26 11:28 693十三、总结: 1.主配置与实体(映射)配置: 关于这些配置 ... -
hiberante入门(十六):一些细节理论
2010-08-26 11:26 746十二、一些细节问题分 ... -
hiberante入门(十四):缓存2
2010-08-26 11:24 426>>步骤四、测试二 ... -
hiberante入门(十四):缓存1
2010-08-26 11:10 7601.模拟缓存并简要说明缓存实现原理 在myhibernate ... -
hiberante入门(十三):懒加载
2010-08-26 11:07 9274.懒加载: 在前面我们已经对懒加载有所提及,现在再借助一个 ... -
hiberante入门(十二):继承关系2
2010-08-26 11:03 963上接hiberante入门(十二 ... -
hiberante入门(十二):继承关系1
2010-08-26 11:01 8253.继承关系: 在前面的部门员工实例中,我们设定的员工只是普 ... -
hibernate入门(十一):级联操作inversin属性
2010-08-26 10:56 1501九、关联关系中的高级应用 1.级联操作: 在前面的一对多 ... -
hiberante入门(十):其它集合类型
2010-08-26 10:53 762八、其它集合类型 说明:在前面我们已经使用过set集合类型, ... -
hibernate入门(九):组件关系映射
2010-08-26 10:51 7735.组件关系映射: 典型实例:每个人有不同的名字,或者多个人 ... -
hibernate入门(八):多对多
2010-08-26 10:48 6444.多对多关系映射: 典型实例:一个学生可以有多个老师 ... -
hibernate入门(七):一对一
2010-08-26 10:42 7213.一对一关系映射: 典型的实例:一个人有一个身份证,而一个 ... -
hibernate入门(六):一对多
2010-08-26 10:36 6872.一对多关系映射: 上面提到的多个员工对应于一个部门,是多 ... -
hibernate入门(五):多对一
2010-08-26 10:32 6421.多对一关系映射: 一个部门有可以有多个员工,而一个员工只 ... -
hibernate入门(四):HQL QBC初步
2010-08-26 10:22 909四 完善工具类及HQL QBC ... -
hibernate入门(三):对象的三种状态
2010-08-26 10:20 686三 Session中的主要方法 ... -
hibernate入门(二):优化代码
2010-08-26 10:17 764二 优化代码 1.为会么要优化 在前面我们已经知道,获取S ... -
hibernate入门(一):第一个应用实例
2010-08-26 10:15 876一 第一个应用实例 1.搭建环境:新建一个名为Hiberna ...
相关推荐
在这个DEMO中,Hibernate使用了Annotation注解,可以直接在实体类上定义数据库表的相关属性,简化了数据库模型的定义。 ExtJS是一个富客户端JavaScript框架,它提供了丰富的组件库和布局管理,能够构建出美观、交互...
NULL 博文链接:https://86asm.iteye.com/blog/493165
hiberante-4.2.3-part4
hiberante-4.2.3-part3
### Hibernate中的五大核心接口 #### 一、概述 在Hibernate框架中,存在五大核心接口,它们分别是:`Session`、`SessionFactory`、`Transaction`、`Query` 和 `Configuration`。这些接口对于Hibernate的正常运行至...
在本篇博文中,我们将深入探讨Hibernate框架中的一个重要特性——一对一(One-to...继续探索Hibernate的其他功能,如多对一、多对多关系映射,以及缓存策略、事务管理等,将有助于提升你在Java开发中的数据库操作能力。
hiberante4.2.3-part2
hiberante3 注解帮助文档hiberante3 注解帮助文档hiberante3 注解帮助文档hiberante3 注解帮助文档hiberante3 注解帮助文档
最新springboot2基础hiberante5完整项目,打包jar,运行jsp,包括后台与前台,拦截器,登录,后台下载就可以使用,注意不是jpa,里面有完整Dao,千万级数据项目分离的代码,为了适合老项目开发特意集成hiberante5....
在开始事务后,所有的数据库操作都在这个事务的范围内进行,直到事务被提交或回滚。 4. `endTransaction(boolean success)`:根据参数`success`决定是否提交事务。如果`success`为`true`,则提交事务;否则,回滚...
标题中的“hibernate - one to many - update”指的是Hibernate框架中关于一对一(One-to-Many)关系映射和更新操作的知识点。在Java开发中,Hibernate是一个流行的对象关系映射(ORM)工具,它允许开发者用面向对象...
五、Hibernate的优势 1. 隐藏了数据库访问细节,提高了开发效率。 2. 提供了面向对象的查询语言HQL,使得查询更直观。 3. 支持级联操作,简化了对象关系的维护。 4. 内置缓存机制,提高性能。 5. 支持多种数据库,...
Hibernate Tools是一套全新而且完整的面向Hibernate3的工具集合,它包含了Eclipse插件和Ant编译流程。Hibernate Tools是JBoss Tools的核心组件,所以他也是JBoss Developer Studio的一部分
《深入理解Hibernate源码与配置》 Hibernate,作为一款强大的对象关系映射(ORM)框架,深受Java开发者喜爱。本文将结合"hibernate源码"和"hibernate配置"两个核心主题,深入探讨Hibernate的工作原理及配置细节,...
**五、会话工厂与会话** Hibernate使用`SessionFactory`来创建`Session`对象,`Session`是与数据库交互的入口。会话负责执行CRUD操作,如保存、更新、删除和查询实体。 **六、查询语言HQL** Hibernate Query ...
7. **事务管理**:Hibernate提供了对JTA(Java Transaction API)和JDBC事务的支持,可以方便地进行事务控制。 8. **事件监听器**:Hibernate允许注册事件监听器,如`PreUpdateEventListener`和`...
Spring 提供了声明式事务管理,可以在方法级别或类级别定义事务边界。当方法执行时,Spring 自动处理事务的开始、提交或回滚,根据是否有异常发生。 在实际应用中,我们可能还需要配置数据源、日志记录、错误处理、...
标题“Hiberante3相关文档”表明了主要讨论的是关于Hibernate3这一持久化框架的资料集合,可能涵盖了多个方面,如查询语言、缓存机制以及数据加载策略。 描述中的“Hiberante3_HQL”提示我们将会涉及到Hibernate...