Hibernate的事务与C3P0的配置

来源:互联网 发布:3DM看门狗卡顿优化补丁 编辑:程序博客网 时间:2024/05/20 11:22

在hibernate开发中配置c3p0 数据库连接池

         hibernate框架内部使用默认数据库连接池 DriverManagerConnectionProvider 提供

使用c3p0 修改hibernate 默认的 ConnectionProvider

         步骤:

         1、 导入jar包 hibernate解压目录/lib/optional/c3p0/c3p0-0.9.1.jar

         2、 配置hibernate.cfg.xml

                   <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>

         3、 配置c3p0 详细参数

                   #hibernate.c3p0.max_size 2

                   #hibernate.c3p0.min_size 2

                   #hibernate.c3p0.timeout 5000  

                   #hibernate.c3p0.max_statements100

                   #hibernate.c3p0.idle_test_period3000

                   #hibernate.c3p0.acquire_increment2

                   #hibernate.c3p0.validatefalse

         注:在hibernate解压目录中的project\etc\hibernate.properties文件中有所有可以配置的常量。

 

数据库并发事务问题

         事务的四大特性(ACID):原子性、一致性、隔离性、 持久性

         事务隔离性引发问题: 脏读、不可重复读、幻读

                   * 脏读 : 一个事务读取另一个事务 未提交数据

                   * 不可重复读: 一个事务 读取另一个事务 已经提交数据(update)

                   * 幻读 : 一个事务 读取 另一个事务已经提交 插入数据 (insert)

                   * 丢失更新:两个事务同时修改一条数据,后提交事务覆盖了之前的提交结果。

 

事务隔离级别可以解决隔离性引发问题:

         * READ_UNCOMMITED  会发生所有隔离问题

         * READ_COMMITTED  会阻止脏读发生,但是会发生 不可重复读和幻读

         * REPEATABLE_READ  会阻止脏读和不可重复读,会发生幻读

         * SERIALIZABLE  以串行方式处理事务,同一时间只有一个事物,没有并发,没有隔离问题(效率很低)

 

         Mysql 数据库默认级别REPEATABLE_READ ,Oracle 数据库默认级别 READ_COMMITTED

 

hibernate提供hibernate.connection.isolation属性,用来修改数据库默认隔离级别,取值 1 2 4 8

         1—Read uncommitted isolation

         2—Read committed isolation

         4—Repeatable read isolation

         8—Serializable isolation

*  mysql 默认是4 , oracle 默认 2

hibernate.cfg.xml 修改隔离级别

         <propertyname="hibernate.connection.isolation">2</property>

 

解决丢失更新问题: 两种方法(悲观锁和乐观锁)    

         1) 悲观锁原理使用数据库底层锁机制,对于要修改的数据,在查询时加锁,此时数据只有加锁的                                               事务可以修改,而其他事务无法再对数据加锁

                   数据库锁分为读锁(共享锁)写锁(排它锁)

                   对于一个表数据可以加多个共享锁,但是只能加一个排它锁,排它锁和任何锁都是互斥

                                                                                                      注:在修改数据时,会自动为数据添加排它锁

         通过查询添加共享锁和排他锁

                   select * from customer lock in share mode ;  添加共享锁

                   select * from customer for update ; 添加排它锁

        

         hibernate 提供了悲观锁机制:Object get(Class clazz,Serializable id,LockMode lockMode)

                   例:Customer customer = (Customer) session.get(Customer.class, 2,LockMode.UPGRADE);

                   说明:LockMode.UPGRADE(排它锁)已过时

         悲观锁可以保证同一时间 只有一个人在修改,不会丢失更新 (缺点:效率很低)

 

         2) 乐观锁原理: 为数据添加一列版本字段,每次修改数据后版本+1(当版本不一致无法修改)

                  优点:不依赖数据库底层锁机制,可以并发修改。乐观锁是现在企业开发中常用的。

         方式: hibernate在hbm文件中 通过<version> 配置乐观锁字段

         例:在Customer类中添加 ver版本字段

                  在Customer.hbm.xml 配置版本字段 <versionname="ver"></version>

        

Session 的管理   

         hibernate框架提供三种 session管理方式

         第一种  Session 对象的生命周期与本地线程(ThreadLocal )绑定

         第二种 Session 对象的生命周期与 JTA 事务绑定(分布式事务<一个事务有多个数据库连接>,必须                          使用分布式服务器 JBOSS、WebLogic )

         第三中 Hibernate 委托程序管理 Session 对象的生命周期

        

web程序中,Session对象生命周期都是与当前线程进行绑定的,只要线程结束了,session就没有了。

         之前我们获取session的方式是通过SessionFactory的openSession()方法随机从数据库连接池中获取一个         连接构造Session对象,但是如果想要获取的session与当前线程绑定就要进行以下配置。

         1) 配置 hibernate.cfg.xml

                   <!-- 配置Session 与当前线程 绑定 -->

                   <property name="hibernate.current_session_context_class">thread</property>

         2) 在程序中 通过SessionFactory的getCurrentSession()方法获得Session对象(其实就是从ThreadLocal                 中获得一个对象 )

注:当使用SessionFactory提供 getCurrentSession()方法时,不用手动的去关闭session,因为当Transaction         提交后,Session 会自动关闭。

 

session与线程绑定与三层架构

         如果简单对web开发分成,可以粗略分为三层:web层、业务层、持久层。对于数据库的操作应该是在持久层,但是问题是在实际开发中的事务管理并不一定在持久层,我们经常在业务层与web层进行控制事务,大多在业务层。由于一次请求应该由服务器进行处理,业务层中有很多业务操作,只要有一个操作失败了,就应该回滚。所以事务应该放到业务层(事务是围绕业务的)。

         如果在业务层开启了事务,那么持久层为了保证是在业务层开启的事务中完成的,就需要使用同一个session。所以业务层就要给持久层传递session,这时就要用到threadlocal,将session与线程绑定。

原创粉丝点击