spring+mybatis之声明式事务管理初识(小实例)
前几篇的文章都只是初步学习spring和mybatis框架,所写的实例也都非常简单,所进行的数据访问控制也都很简单,没有加入事务管理.这篇文章将初步接触事务管理.
1.事务管理
理解事务管理之前,先通过一个例子讲一下什么是事务管理:取钱。
比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱;然后ATM出1000元钱。这两个步骤必须是要么都执行要么都不执行。如果银行卡扣除了1000块但是ATM出钱失败的话,你将会损失1000元;如果银行卡扣钱失败但是ATM却出了1000块,那么银行将损失1000元。所以,如果一个步骤成功另一个步骤失败对双方都不是好事,如果不管哪一个步骤失败了以后,整个取钱过程都能回滚,也就是完全取消所有操作的话,这对双方都是极好的。 事务就是用来解决类似问题的。事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。 在企业级应用程序开发中,事务管理必不可少的技术,用来确保数据的完整性和一致性。
事务有四个特性:ACID
- 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
- 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
- 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
- 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。
2.小实例工程
(1)工程目录:

(2)建立数据库transaction,建立一张user表:

(3)建立User.java类:
package com.gnc.model;
public class User {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User() {
}
public User(String id, String name) {
super();
this.id = id;
this.name = name;
}
}
(4)建立UserDao.java数据访问接口:
package com.gnc.dao; import java.util.List;
import java.util.Map; import com.gnc.model.User; public interface UserDao {
public int countAll();
public void insertUser(User user);
public List<User> getAllUser();
public User getById(String id);
public void deleteUser(String id);
public void updateUser(Map<String,Object> map); }
(5)建立实现UserDaoImpl.java类:
package com.gnc.daoImpl; import java.util.List;
import java.util.Map; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import com.gnc.dao.UserDao;
import com.gnc.mapper.UserMapper;
import com.gnc.model.User; @Service("userDao")
public class UserDaoImpl implements UserDao {
@Autowired
private UserMapper userMapper; public int countAll() {
return this.userMapper.countAll();
} @Override
public void insertUser(User user) {
this.userMapper.insertUser(user); } @Override
public List<User> getAllUser() {
return this.userMapper.getAllUser();
} @Override
public User getById(String id) {
return this.userMapper.getById(id);
} @Override
public void deleteUser(String id) {
this.userMapper.deleteUser(id); } @Override
public void updateUser(Map<String, Object> map) {
this.userMapper.updateUser(map);
} }
(6)建立UserDao接口访问映射文件UserDaoMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gnc.mapper.UserMapper"> <parameterMap id="parameterMapUser" type="com.gnc.model.User" >
<parameter property="id" />
<parameter property="name" />
</parameterMap> <resultMap id="resultMapUser" type="com.gnc.model.User" >
<result property="id" column="id" />
<result property="name" column="name" />
</resultMap> <insert id="insertUser" parameterMap="parameterMapUser">
INSERT INTO user(id,name)
VALUES(?,?)
</insert>
<select id="countAll" resultType="int">
select count(*) c from user;
</select>
<select id="getAllUser" resultMap="resultMapUser">
SELECT * FROM user
</select>
<select id="getById" parameterType="String" resultMap="resultMapUser">
SELECT * FROM user
WHERE id=#{value}
</select>
<delete id="deleteUser" parameterType="String">
DELETE FROM user
WHERE id=#{value}
</delete>
<update id="updateUser" parameterType="java.util.Map">
UPDATE user
SET name=#{name}
WHERE id=#{id}
</update>
</mapper>
(7)建立UserService.java接口类:
package com.gnc.service;
import java.util.Map;
import com.gnc.model.User;
public interface UserService {
public int countAll();
public void insertUser(User user);
public void update_insert(Map map, User user);
}
(8)建立UserServiceImpl.java实现类:
package com.gnc.serviceImpl; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import com.gnc.dao.UserDao;
import com.gnc.model.User;
import com.gnc.service.UserService; @Service("userService")
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao; public int countAll() {
return this.userDao.countAll();
} @Override
public void insertUser(User user) {
this.userDao.insertUser(user);
throw new RuntimeException("Error");
} @Override
public void update_insert(Map map, User user) {
this.userDao.updateUser(map);
this.userDao.insertUser(user);
throw new RuntimeException("Error"); } }
(9)建立mybatis配置文件MyBatis-Configuration.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<mappers>
<mapper resource="UserDaoMapper.xml"/>
</mappers>
</configuration>
(10)建立数据库配置文件config.properties:
db.driverClass=org.gjt.mm.mysql.Driver
db.jdbcUrl=jdbc:mysql://localhost:3306/transaction
db.user=root
db.password=geningchao
#
db.initialPoolSize=20
db.maxIdleTime=60
db.maxPoolSize=200
db.minPoolSize=50
#
db.acquireIncrement=3
db.acquireRetryDelay=1000
db.acquireRetryAttempts=30
db.breakAfterAcquireFailure=false
(11)建立spring配置文件applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> <!-- 加载配置文件 -->
<context:property-placeholder location="config.properties" />
<!-- 指定spring注解注入层 -->
<context:component-scan base-package="com.gnc" />
<!-- 数据库连接池管理 -->
<bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${db.driverClass}"></property>
<property name="jdbcUrl" value="${db.jdbcUrl}"></property>
<property name="user" value="${db.user}"></property>
<property name="password" value="${db.password}"></property> <property name="initialPoolSize" value="${db.initialPoolSize}"></property> <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
<property name="maxIdleTime" value="${db.maxIdleTime}"></property>
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize" value="${db.maxPoolSize}"></property>
<property name="minPoolSize" value="${db.minPoolSize}"></property> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement" value="${db.acquireIncrement}"></property>
<!--两次连接中间隔时间,单位毫秒。Default: 1000 -->
<property name="acquireRetryDelay" value="${db.acquireRetryDelay}"></property>
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts" value="${db.acquireRetryAttempts}"></property>
<!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
获取连接失败后该数据源将申明已断开并永久关闭。Default: false -->
<property name="breakAfterAcquireFailure" value="${db.breakAfterAcquireFailure}"></property>
</bean> <!-- ================================事务相关控制================================================= --> <bean name="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="c3p0DataSource"></property>
</bean> <tx:advice id="userTxAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="delete*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException" />
<tx:method name="insert*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.RuntimeException" />
<tx:method name="update*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="find*" propagation="SUPPORTS" />
<tx:method name="get*" propagation="SUPPORTS" />
<tx:method name="select*" propagation="SUPPORTS" />
</tx:attributes>
</tx:advice> <aop:config>
<aop:pointcut id="pc"
expression="execution(public * com.gnc.service.*.*(..))" /> <!--把事务控制在Service层 -->
<aop:advisor pointcut-ref="pc" advice-ref="userTxAdvice" />
</aop:config> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="c3p0DataSource" />
<property name="configLocation" value="MyBatis-Configuration.xml" />
</bean> <bean class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.gnc.mapper.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean> </beans>
(12)建立测试类UserServiceTest.java:
package com.gnc.test; import java.util.HashMap;
import java.util.Map; import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.gnc.model.User;
import com.gnc.service.UserService; public class UserServiceTest { @Test
public void userServiceTest(){
@SuppressWarnings("resource")
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService)context.getBean("userService");
User user =new User();
user.setId("003");
user.setName("樱木花道"); Map map=new HashMap();
map.put("id", "001");
map.put("name", "方舟子");
try {
System.out.println(userService.countAll());
userService.update_insert(map, user);
} catch (Exception e) {
e.printStackTrace();
} }
}
3.工程分析
该工程属于声明式事务管理,事务管理的主要配置是写在spring的配置文件当中,工程运行时,先加载spring配置文件,通过spring配置文件得到mybatis配置文件,得到映射文件,进行事务处理以及书屋管理.但是这种事务管理方式限制了包的分级结构和函数名的前缀,所以一般情况下,我们使用注解式事务管理,注解式事务管理实例将在下一章节给出并进行说明!
以上仅是个人观点,若有不对,敬请扶正!
spring+mybatis之声明式事务管理初识(小实例)的更多相关文章
- spring+mybatis之注解式事务管理初识(小实例)
1.上一章,我们谈到了spring+mybatis声明式事务管理,我们在文章末尾提到,在实际项目中,用得更多的是注解式事务管理,这一章将学习一下注解式事务管理的有关知识.注解式事务管理只需要在上一节的 ...
- Spring—SSJ集成&声明式事务管理
1. 课程介绍 1. SSJ集成;(掌握) 2. 声明式事务管理;(掌握) 什么是三大框架 2.1. ssh Struts/Struts2 Spring Hibernate 2.2. ss ...
- 全面分析 Spring 的编程式事务管理及声明式事务管理
开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本 ...
- 全面分析 Spring 的编程式事务管理及声明式事务管理--转
开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本 ...
- Spring编程式事务管理及声明式事务管理
本文将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. Spring 事务属性分析 事务管理 ...
- spring事物配置,声明式事务管理和基于@Transactional注解的使用
http://blog.csdn.net/bao19901210/article/details/41724355 http://www.cnblogs.com/leiOOlei/p/3725911. ...
- spring声明式事务管理方式( 基于tx和aop名字空间的xml配置+@Transactional注解)
1. 声明式事务管理分类 声明式事务管理也有两种常用的方式, 一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解. 显然基于注解的方式更简单易用,更清爽. ...
- spring事务配置,声明式事务管理和基于@Transactional注解的使用(转载)
原文地址:http://blog.csdn.net/bao19901210/article/details/41724355 事务管理对于企业应用来说是至关重要的,好使出现异常情况,它也可以保证数据的 ...
- 【Spring】Spring的事务管理 - 2、声明式事务管理(实现基于XML、Annotation的方式。)
声明式事务管理 文章目录 声明式事务管理 基于XML方式的声明式事务 基于Annotation方式的声明式事务 简单记录 - 简单记录-Java EE企业级应用开发教程(Spring+Spring M ...
随机推荐
- MySql存储过程的使用
MySql存储过程跟sql server 有一定的区别,使用说明和步骤如下 使用说明 创建存储过程 MySQL中,创建存储过程的基本形式如下: CREATE PROCEDURE sp_name ([p ...
- C++ cout 输出小数点后指定位数
在C中我们可以使用 printf("%.2lf",a);但在C++中是没有格式操作符的,该如何操作: C++使用setprecision()函数,同时必须包含头文件iomanip, ...
- matlab中使用elseif和if嵌套的对比
% 目标: % 判定成绩等级 %定义变量 % 输入:分数grade %清除变量或指令 clc; % 允许用户输入参数 disp ('该功能练习if语句'); disp ('输入你的成绩,系统将判定等级 ...
- [Kafka] - Kafka Java Consumer实现(一)
Kafka提供了两种Consumer API,分别是:High Level Consumer API 和 Lower Level Consumer API(Simple Consumer API) H ...
- 【WCF】服务并发中的“可重入模式”
WCF服务实例的并发模式是在服务实现类上,使用 ServiceBehaviorAttribute 的 ConcurrencyMode 属性来指定.其值由 ConcurrencyMode 枚举来界定,这 ...
- 用Ajax实现自动刷新news功能
这是Ajax应用的一个小实例:在页面中自动刷新功能,比如整个新闻页面中某一个小版块的内容,无需刷新整个页面就可以自动更新: 1.首先创建简单的页面元素: <body> <input ...
- 每天一个Linux命令(11)--nl命令
nl命令在Linux系统中用来计算文件中行号.nl可以将输出的文件内容自动的加上行号,其默认的结果与cat -n 有点不太一样,nl可以将行号做比较多的显示设计,包括位数与是否自动不起0等等的功能. ...
- tmux进阶之tmuxinator
tmux进阶之tmuxinator 作者:crane-yuan 日期:2017-03-03 前言 tmuxinator是tmux的配置管理工具,解决了tmux服务器关机后session丢失问题.tmu ...
- 【转】Python 中 Iterator和Iterable的区别
Python中 list,truple,str,dict这些都可以被迭代,但他们并不是迭代器.为什么? 因为和迭代器相比有一个很大的不同,list/truple/map/dict这些数据的大小是确定的 ...
- 双系统win7和ubuntu14.04进入了grub rescue>
可以跳过的废话:最近在学习caffe,需要在linux下安装cuda,sudo apt-get install cuda后,出现了由于根目录/空间不足而失败的情况. 于是想把win7下80G的一个盘格 ...