Spring+Hibernate : 声明式事务

来源:互联网 发布:php 判断是否刷新页面 编辑:程序博客网 时间:2024/06/08 00:33

本博文是作为初学者来学习和总结SH的声明式事务,

  1. Spring 中配置数据源的4中方式,主要关注c3p0数据源;
  2. Spring 的PropertyPlaceholderConfigurer :将properties属性值读入到xml文件中;
  3. 事务的常见六种传播特性介绍;
  4. Spring 和 Hibernate 集成声明式事务的四大步骤;
  5. Spring 和 Hibernate 集成过程中版本冲突问题;
  6. 项目代码演示;
  7. 总结语;

  1. Spring中配置数据源

1.1 Spring 自带的数据源: DriverManagerDataSource;
spring自身提供了三个没有连接池功能的数据源类(均位于org.springframework.jdbc.datasource 包中)

  • DriverManagerDatasource
  • SimpleDriverDatasource
  • SingleConnectionDatasource

    xml代码:

    <bean id="dataSource"             <class="org.springframework.jdbc.datasource.DriverManagerDataSource">             <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />          <property name="url" value="jdbc:oracle:thin:@localhost:1521:ORCL" />          <property name="username" value="scott" />             <property name="password" value="****" />      </bean>  

1.2 第三方数据源:dbcp 数据源和 c3p0数据源
Apache CommonsDBCP数据源地址
c3p0数据源地址

1.2.1 dbcp
dbcp的配置依赖于2个jar包commons-dbcp.jar,commons-pool.jar。

xml配置:

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"                     destroy-method="close">                 <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />          <property name="url" value="jdbc:oracle:thin:@localhost:1521:ORCL" />          <property name="username" value="scott" />             <property name="password" value="****" />            </bean>   

1.2.2 c3p0数据源

xml配置:

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"                         destroy-method="close">                    <property name="driverClass" value=" oracle.jdbc.driver.OracleDriver "/>                    <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:ORCL"/>                    <property name="user" value="scott"/>                    <property name="password" value="****"/>             </bean>   

c3p0参数配置:
官网上对各个参数及其意义及如何配置说的很清楚;

这里写图片描述

  • acquireIncrement:当连接池中的连接用完时,C3P0一次性创建新连接的数目;

  • acquireRetryAttempts:定义在从数据库获取新连接失败后重复尝试获取的次数,默认为30;

  • acquireRetryDelay:两次连接中间隔时间,单位毫秒,默认为1000;

  • autoCommitOnClose:连接关闭时默认将所有未提交的操作回滚。默认为false;

  • automaticTestTable
    C3P0将建一张名为Test的空表,并使用其自带的查询语句进行测试。

  • breakAfterAcquireFailure:获取连接失败将会引起所有等待获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调
    用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。默认为
    false;

  • checkoutTimeout:当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒,默认为0;

  • connectionTesterClassName
    通过实现ConnectionTester或QueryConnectionTester的类来测试连接,类名需设置为全限定名。默认为
    com.mchange.v2.C3P0.impl.DefaultConnectionTester;

  • idleConnectionTestPeriod:隔多少秒检查所有连接池中的空闲连接,默认为0表示不检查;

  • initialPoolSize:初始化时创建的连接数,应在minPoolSize与maxPoolSize之间取值。默认为3;

  • maxIdleTime:最大空闲时间,超过空闲时间的连接将被丢弃。为0或负数则永不丢弃。默认为0;

  • maxPoolSize:连接池中保留的最大连接数。默认为15;

  • maxStatements:JDBC的标准参数,用以控制数据源内加载的PreparedStatement数量。但由于预缓存的Statement属
    于单个Connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素,如果maxStatements与
    maxStatementsPerConnection均为0,则缓存被关闭。默认为0;

  • maxStatementsPerConnection:连接池内单个连接所拥有的最大缓存Statement数。默认为0;

  • numHelperThreads:C3P0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能,通过多线程实现多个操作同时被执行。默认为3;

  • preferredTestQuery:定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个参数能显著提高测试速度。测试的表必须在初始数据源的时候就存在。默认为null;

  • propertyCycle: 用户修改系统配置参数执行前最多等待的秒数。默认为300;

  • testConnectionOnCheckout:因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的时候都
    将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
    等方法来提升连接测试的性能。默认为false;

  • testConnectionOnCheckin:如果设为true那么在取得连接的同时将校验连接的有效性。默认为false。


1.4 JNDI数据源
Spring应用程序通常部署在Java EE应用服务器中,如JBoss,Tomcat这样的Web容器。这些服务器允许配置通过jndi获取数据源。

在spring配置文件中如下设置:

<beans>    <jee:jndi-lookup id="datasource" jndi-name="java:comp/env/jdbc/myDataSource"/></beans>

在服务器中的配置以tomcat为例:

<Resource     name="jdbc/myDataSource"     type="javax.sql.DataSource"    driverClassName="oracle.jdbc.driver.OracleDriver"    url="jdbc:oracle:thin:@193.23.42.6:1521:myDataSource"    username="scott"     password="****"     maxActive="80" />


  • Spring 的PropertyPlaceholderConfigurer :将properties属性值读入到xml文件中;

2.1 在这之前我们先看看Hibernate的文件 hibernate.cfg.xml 是怎么配置,

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-configuration PUBLIC        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration>    <session-factory>        <!-- Database connection settings -->        <property name="connection.driver_class">oracle.jdbc.OracleDriver</property>        <property name="connection.url">jdbc:oracle:thin:@localhost:1521:ORCL</property>        <property name="connection.username">scott</property>        <property name="connection.password">qian</property>        <!-- JDBC connection pool (use the built-in) -->        <property name="connection.pool_size">1</property>        <!-- SQL dialect -->        <property name="dialect">org.hibernate.dialect.OracleDialect</property>        <!-- Disable the second-level cache  -->        <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>        <!-- Echo all executed SQL to stdout -->        <property name="show_sql">true</property        <property name="hbm2ddl.auto">update</property>        <mapping resource="com/qian/domain/User.hbm.xml"/>     </session-factory></hibernate-configuration>

2.2 接下来,我们以读取配置文件的方式配置数据源,那么hibernate.cfg.xml如下:

hibernate.cfg.xml

<hibernate-configuration>    <session-factory>        <!-- 配置hibernate基本信息 -->          <!-- 1.数据源配置在IOC容器中,此处不需要额外配置 -->          <!-- 2.关联的.hbm.xml文件也可以在IOC容器配置SessionFactory时配置 -->          <!-- 3.此处配置hibernate的基本信息:数据库方言、SQL显示及格式化,及生成数据表的策略,二级缓存等 -->         <!-- SQL dialect -->        <property name="dialect">org.hibernate.dialect.OracleDialect</property>        <!-- Disable the second-level cache  -->        <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>        <!-- Echo all executed SQL to stdout -->        <property name="show_sql">true</property>        <property name="hibernate.format_sql">true</property    <property name="hibernate.hbm2ddl.auto">update</property>        <mapping resource="com/spring/trans/domain/User.hbm.xml"/>    </session-factory></hibernate-configuration>

2.3 使用c3p0在 spring IOC容器中显示配置

applicationContext.xml

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">    <property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/>    <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:ORCL"/>    <property name="user" value="scott"/>    <property name="password" value="qian"/>    <property name="initialPoolSize" value="3"/></bean>     

2.4 将数据源的配置信息放入到 jdbc.properties中如下:

jdbc.properties

jdbc.driver=oracle.jdbc.driver.OracleDriverjdbc.url=jdbc:oracle:thin:@localhost:1521:ORCLjdbc.userName=scottjdbc.password=qianjdbc.initialPoolSize=3

2.5 应用spring的PropertyPlaceholderConfigurer将上下文(配置文件) 中的属性值在 xml 文件中以 ${key} 形式读入,

第一种方式:

<bean id="" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">        <property name="location">            <value>classpath:jdbc.properties</value>        </property></bean>

如要读取读个配置文件 使用方法setLocations:

<bean id="" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">        <property name="locations">            <list>                <value>classpath:jdbc.properties</value>                <value>classpath:infors.properties</value>            </list>        </property></bean>

第二种方式:为了简化上述这样的配置,Spring 给出了<context: property-placeholder/> 元素,因此上式可以简化为:

<context:property-placeholder location="classpath:jdbc.properties"/>
<context:property-placeholder location="classpath:jdbc.properties,classpath:infors.properties"/>

此时,数据源配置如下:

<bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">        <property name="driverClass" value="${jdbc.driver}"/>    <property name="jdbcUrl" value="${jdbc.url}"/>    <property name="user" value="${jdbc.userName}"/>    <property name="password" value="${jdbc.password}"/>    <property name="initialPoolSize" value="${jdbc.initialPoolSize}"/></bean>

如要改动相关信息,我们只需要去改properties文件即可;



  • 事务传播特性介绍

事务:是程序中一系列严密的操作,所有操作执行必须成功完成,否则在每个操作所做的更改将会被撤销,(要么成功,要么失败)。
事务特性分为四个:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持续性(Durability)简称ACID。
Spring事务对数据库事务操作的一次封装,相当于把使用JDBC代码开启、提交、回滚事务进行了封装。

事务的传播特性: 是保证事务是否开启,业务逻辑是否使用同一个事务的保证。

  • PROPAGATION_REQUIRED:
    • 如果存在一个事务,则支持当前事务。如果没有事务则开启
  • PROPAGATION_REQUIRES_NEW:
    • 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
  • PROPAGATION_SUPPORTS:
    • 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
    • PROPAGATION_NOT_SUPPORTED: 总是非事务地执行,并挂起任何存在的事务。
  • PROPAGATION_MANDATORY:
    • 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
  • PROPAGATION_NEVER:
    • 总是非事务地执行,如果存在一个活动事务,则抛出异常

这里写图片描述


  • Spring 和 Hibernate 集成声明式事务的四大步骤;

4.1 配置SessionFactory, 将hibernate.cfg.xml 文件交给Spring,通过Spring提供的 LocalSessionFactoryBean配置Hibernate的SessionFactory

<!-- Step 0 配置自己的dataSource, 早期我们在hibernate.cfg.xml中配置的直接 --><!-- 把hibernate.cfg.xml给了spring就好,现在我们在spring applicationContext.xml配置数据源 --><!-- ** myDataSource ** --><bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">        <property name="driverClass" value="${jdbc.driver}"/>    <property name="jdbcUrl" value="${jdbc.url}"/>    <property name="user" value="${jdbc.userName}"/>    <property name="password" value="${jdbc.password}"/>    <property name="initialPoolSize" value="${jdbc.initialPoolSize}"/></bean>
<!--Step 1:  配置Hibernate的SessionFactory,通过spring提供的 LocalSessionFactoryBean配置--><!-- ** mySessionFactory** --><bean id="mySessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">    <property name="dataSource">        <!-- step 0中的数据源名称 -->        <ref bean="myDataSource"/>    </property>    <property name="configLocation">        <value>classpath:hibernate.cfg.xml</value>    </property>    <!-- 如果我们不在hibernate.cfg.xml中配置User.hbm.xml和Log.hbm。xml我们也可以在这配置 -->    <!--      <property name="mappingLocations">        <value>classpath:com/spring/trans/domain/*.hbm.xml</value>    </property>    --></bean>

4.2 配置事务管理器,将spring生产的sessionFactory注入到事务管理器上,

<!--Step 2:  配置 Spring 的声明式事物 -->  <!-- ** myTransactionManager --><bean id="myTransactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">    <property name="sessionFactory">        <!-- step 1中的SessionFactory名称 -->        <ref bean="mySessionFactory"/>    </property></bean>

4.3 配置事务的转播特性

<!--Step 3:  配置事物属性 ,需要事物管理器--> <!-- **myTxAdvice** --><!-- step 2 中的myTransactionManager名称 --><tx:advice id="myTxAdvice" transaction-manager="myTransactionManager">    <tx:attributes>        <tx:method name="add*" propagation="REQUIRED"/>        <tx:method name="delete*" propagation="REQUIRED"/>        <tx:method name="modify*" propagation="REQUIRED"/>        <tx:method name="find*" propagation="REQUIRED" read-only="true"/>    </tx:attributes></tx:advice>

4.4 配置事务的切点,并将事务属性和切点管理起来

<!--Step 4:  配置事物切点,并把事物属性和切点关联起来 --> <aop:config>    <aop:pointcut expression="execution(* com.spring.trans.manager.*.*(..))" id="myPointcut"/>    <!-- step 3: myTxAdvice -->    <aop:advisor advice-ref="myTxAdvice" pointcut-ref="myPointcut"/></aop:config>

注意:
最后将将spring生成的SessionFactory注入给IOC容器中的实体bean,要不它找不到SessionFactory。

 <bean id="userManagerImpl" class="com.spring.trans.manager.UserManagerImpl">    <!-- ** 将spring生成的sessionFactory注入到Ioc需要使用的类中; -->        <property name="sessionFactory">            <ref bean="mySessionFactory"/>        </property>        <property name="logManager">            <ref bean="logManagerImpl"/>        </property> </bean>


  • Spring 和 Hibernate 集成过程中版本冲突问题;

    5.1 在继承 Spring 和Hibernate即使都配置对了,还是会报各种异常,大致为,类找不到,这个好解决,加入相应的架包就可以解决; BeanCreateException等异常,我原来用的Spring 4.3 和Hibernate 5.1.10 一直出现异常,后将Hibernate 换成最新的Hibernate5.2.11就好了;所以很多时候,我们要关注是不是版本冲突导致的;



  • 项目代码示例:

这里就展示下项目结构和用到的架包,如果有需要源码的朋友,可以留邮箱或者在这里下载;

项目结构:
这里写图片描述

Spring4.3.0架包:
这里写图片描述

Hibernate5.2.11架包:
这里写图片描述

applicationContext-commons.xml文件内容

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns:tx="http://www.springframework.org/schema/tx"     xmlns:aop="http://www.springframework.org/schema/aop"     xmlns:context="http://www.springframework.org/schema/context"     xsi:schemaLocation="     http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-4.3.xsd     http://www.springframework.org/schema/context     http://www.springframework.org/schema/context/spring-context-4.3.xsd     http://www.springframework.org/schema/tx     http://www.springframework.org/schema/tx/spring-tx-4.3.xsd     http://www.springframework.org/schema/aop     http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">    <!--      <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">        <property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/>        <property name="jdbcUrl" value="jdbc:oracle:thin:@localhost:1521:ORCL"/>        <property name="user" value="scott"/>        <property name="password" value="qian"/>        <property name="initialPoolSize" value="2"/>    </bean>          -->     <!-- Step 1 -->     <!--      <bean id="" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">        <property name="location">            <value>classpath:jdbc.properties</value>        </property>    </bean>    -->    <context:property-placeholder location="classpath:jdbc.properties"/>    <!-- Step 2 -->    <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">        <property name="driverClass" value="${jdbc.driver}"/>        <property name="jdbcUrl" value="${jdbc.url}"/>        <property name="user" value="${jdbc.userName}"/>        <property name="password" value="${jdbc.password}"/>        <property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>    </bean>    <!-- ========================================================================================================= -->    <!--Step 1:  配置Hibernate的SessionFactory,通过spring提供的 LocalSessionFactoryBean配置-->    <bean id="mySessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">        <property name="dataSource">            <ref bean="myDataSource"/>        </property>        <property name="configLocation">            <value>classpath:hibernate.cfg.xml</value>        </property>        <!-- 如果我们不在hibernate.cfg.xml中配置User.hbm.xml和Log.hbm。xml我们也可以在这配置 -->        <!--          <property name="mappingLocations">            <value>classpath:com/spring/trans/domain/*.hbm.xml</value>        </property>        -->    </bean>    <!--Step 2:  配置 Spring 的声明式事物 -->      <bean id="myTransactionManager"  class="org.springframework.orm.hibernate5.HibernateTransactionManager">        <property name="sessionFactory">            <ref bean="mySessionFactory"/>        </property>    </bean>    <!--Step 3:  配置事物属性 ,需要事物管理器-->     <tx:advice id="myTxAdvice" transaction-manager="myTransactionManager">        <tx:attributes>            <tx:method name="add*" propagation="REQUIRED"/>            <tx:method name="delete*" propagation="REQUIRED"/>            <tx:method name="modify*" propagation="REQUIRED"/>            <tx:method name="find*" propagation="REQUIRED" read-only="true"/>        </tx:attributes>    </tx:advice>    <!--Step 4:  配置事物切点,并把事物属性和切点关联起来 -->     <aop:config>        <aop:pointcut expression="execution(* com.spring.trans.manager.*.*(..))" id="myPointcut"/>        <aop:advisor advice-ref="myTxAdvice" pointcut-ref="myPointcut"/>    </aop:config><!--      <bean id="userManagerImpl" class="com.spring.trans.manager.UserManagerImpl">        <property name="sessionFactory">            <ref bean="mySessionFactory"/>        </property>        <property name="logManager">            <ref bean="logManagerImpl"/>        </property>     </bean>     <bean id="logManagerImpl" class="com.spring.trans.manager.LogManagerImpl">        <property name="sessionFactory">            <ref bean="mySessionFactory"/>        </property>     </bean>--></beans>


补充一点:怎么在Eclipse下配置 Hibernate 和 Spring相应标签的快捷键;

  1. hibernate.cfg.xml 和 *.hbm.xml 快捷键

这里写图片描述

这里写图片描述

在下载的hibernate的文件中,找打这两个文件,
这里写图片描述

在Eclipse–》Preference–》XML–>xml catalog下如下添加:
这里写图片描述

  1. spring的 applicationContext.xml文件快捷键配置类似;
    这里写图片描述


Okay, okay. That is all, maybe too long. If you want to get the source code of this program in the blog, you can download here , or leave your email in the comments for free.

原创粉丝点击