Spring c3p0的测试 和 事物管理 xml配置 (四)

来源:互联网 发布:pop3的端口 编辑:程序博客网 时间:2024/06/06 02:03

一, 使用c3p0配置连接池的xml配置

c3p0.jar 和mchange-commons-java.jar

a.CombopooledDataSource 连接池底层的原理实现 :java

{ComboPooledDataSource datesource=new ComboPooledDataSource();//其实不需要配置文件也行,只是需要写死就okdatesource.setDriverClass("com.mysql.jdbc.Driver");datesource.setJdbcUrl("jdbc:mysql:///message");datesource.setUser("root");datesource.setPassword("");JdbcTemplate jdbcTemplate = new JdbcTemplate(datesource);String sql = "select count(*) from message";int i = jdbcTemplate.queryForInt(sql);System.out.println(i);}


b.spring中配置c3p0的连接池

<!-- 1.配置c3p0 的连接池 --><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><!-- 注入属性值 --><property name="driverClass" value="com.mysql.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql:///message"></property><property name="user" value="root"></property><property name="password" value=""></property></bean><!-- 2.创建jdbcTemplate模板 --><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean><!-- 3.给userDao中注入jdbcTemplate模板 --><bean id="userDao" class="com.gog.c3p0.UserDao"><property name="jdbcTemplate" ref="jdbcTemplate"></property></bean><!-- 4. --><bean id="userService" class="com.gog.c3p0.UserService"><property name="userDao" ref="userDao"></property></bean>


c.userDao中实现对数据库的操作

public class UserDao {private JdbcTemplate jdbcTemplate;public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}public void add(){System.out.println("--> UserDao");String sql = " insert into message values(?,?,?,?)";int rows = jdbcTemplate.update(sql, 72, "GGr", "3", "4");System.out.println("rows"+rows);}}


二,Spring 的事物 的xml配置

tip:
事物是操作数据的一组操作的基本单元,要不然都成功,要不都失败
不考虑隔离性产生读问题 -->多个事物之间不产生影响
(1)编程试事物管理
不常用
(2)声明式事物管理
PlatformTransactionManager 事物管理接口
TransactionDefinition 事物定义信息(隔离,传播,超时,只读)
TransactionStatus事物具体运行状态
1)基于xml配置文件实现
2)注解实现


<!-- 开启注解扫描 --><context:component-scan base-package="com.gog"></context:component-scan><!-- 开启aop注解操作(自动代理) --><aop:aspectj-autoproxy></aop:aspectj-autoproxy><!-- 1.配置c3p0 的连接池 --><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><!-- 注入属性值 --><property name="driverClass" value="com.mysql.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql:///message?useUnicode=true&characterEncoding=utf8"></property><property name="user" value="root"></property><property name="password" value=""></property></bean><!-- 2.创建jdbcTemplate模板 --><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean><!-- 1.xml配置事物管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name = "dataSource" ref="dataSource"></property></bean><!-- 2.xml配置事物的增强 --><tx:advice id="txadvice" transaction-manager="transactionManager"><!-- 做事物操作 --><tx:attributes><!-- 设置进行事物操作的方法匹配规则 --><tx:method name="account*"></tx:method><tx:method name="insert*"></tx:method></tx:attributes></tx:advice><!-- 3.xml配置切面 --><aop:config ><!-- 切入点 --><aop:pointcut expression="execution(* com.gog.tx.service.OrderService.*(..))" id="pointcut1"></aop:pointcut><!-- 切面 --><aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1" ></aop:advisor></aop:config><bean id="orderUser" class="com.gog.tx.dao.OrderUser"><property name="jdbcTemplate" ref="jdbcTemplate"></property></bean><bean id="orderService" class="com.gog.tx.service.OrderService"><property name="orderUser" ref="orderUser"></property></bean>


三:事务的嵌套

通过上面的理论知识的铺垫,我们大致知道了数据库事务和spring事务的一些属性和特点,接下来我们通过分析一些嵌套事务的场景,来深入理解spring事务传播的机制。

假设外层事务 Service A 的 Method A() 调用 内层Service B 的 Method B()

PROPAGATION_REQUIRED(spring 默认)

如果ServiceB.methodB() 的事务级别定义为 PROPAGATION_REQUIRED,那么执行 ServiceA.methodA() 的时候spring已经起了事务,这时调用 ServiceB.methodB(),ServiceB.methodB() 看到自己已经运行在 ServiceA.methodA() 的事务内部,就不再起新的事务。

假如 ServiceB.methodB() 运行的时候发现自己没有在事务中,他就会为自己分配一个事务。

这样,在 ServiceA.methodA() 或者在 ServiceB.methodB() 内的任何地方出现异常,事务都会被回滚。

PROPAGATION_REQUIRES_NEW

比如我们设计 ServiceA.methodA() 的事务级别为 PROPAGATION_REQUIRED,ServiceB.methodB() 的事务级别为 PROPAGATION_REQUIRES_NEW。

那么当执行到 ServiceB.methodB() 的时候,ServiceA.methodA() 所在的事务就会挂起,ServiceB.methodB() 会起一个新的事务,等待 ServiceB.methodB() 的事务完成以后,它才继续执行。

他与 PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为 ServiceB.methodB() 是新起一个事务,那么就是存在两个不同的事务。如果 ServiceB.methodB() 已经提交,那么 ServiceA.methodA() 失败回滚,ServiceB.methodB() 是不会回滚的。如果 ServiceB.methodB() 失败回滚,如果他抛出的异常被 ServiceA.methodA() 捕获,ServiceA.methodA() 事务仍然可能提交(主要看B抛出的异常是不是A会回滚的异常)。

PROPAGATION_SUPPORTS

假设ServiceB.methodB() 的事务级别为 PROPAGATION_SUPPORTS,那么当执行到ServiceB.methodB()时,如果发现ServiceA.methodA()已经开启了一个事务,则加入当前的事务,如果发现ServiceA.methodA()没有开启事务,则自己也不开启事务。这种时候,内部方法的事务性完全依赖于最外层的事务。

PROPAGATION_NESTED

现在的情况就变得比较复杂了, ServiceB.methodB() 的事务属性被配置为 PROPAGATION_NESTED, 此时两者之间又将如何协作呢? 
ServiceB#methodB 如果 rollback, 那么内部事务(即 ServiceB#methodB) 将回滚到它执行前的 SavePoint 而外部事务(即 ServiceA#methodA) 可以有以下两种处理方式:

a、捕获异常,执行异常分支逻辑

void methodA() {         try {             ServiceB.methodB();         } catch (SomeException) {             // 执行其他业务, 如 ServiceC.methodC();         }     }

这种方式也是嵌套事务最有价值的地方, 它起到了分支执行的效果, 如果 ServiceB.methodB 失败, 那么执行 ServiceC.methodC(), 而 ServiceB.methodB 已经回滚到它执行之前的 SavePoint, 所以不会产生脏数据(相当于此方法从未执行过), 这种特性可以用在某些特殊的业务中, 而 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 都没有办法做到这一点。

b、 外部事务回滚/提交 代码不做任何修改, 那么如果内部事务(ServiceB#methodB) rollback, 那么首先 ServiceB.methodB 回滚到它执行之前的 SavePoint(在任何情况下都会如此), 外部事务(即 ServiceA#methodA) 将根据具体的配置决定自己是 commit 还是 rollback









//少钱的方法public void lessMoney(){String sql =" update account set salary=salary-? where id=?";int update = jdbcTemplate.update(sql,100,1);System.out.println(update);String sql2 = "SELECT * FROM account where ID = ?";Account account = jdbcTemplate.queryForObject(sql2, new MyAccount(),1);System.out.println(account);}//多钱方法public void moreMoney(){String sql =" update account set salary=salary+? where id=?";int update = jdbcTemplate.update(sql,100,2);System.out.println(update);String sql2 = "SELECT * FROM account where ID = ?";Account account = jdbcTemplate.queryForObject(sql2, new MyAccount(),2);System.out.println(account);}










原创粉丝点击