ibatis 批量更新事物控制+批量提交问题

4157人阅读
IBatisNet(9)
一、事务概念
&&& 事务是一种机制、是一种操作序列,它包含了一组数据库操作命令,这组命令要么全部执行,要么全部不执行。因此事务是一个不可分割的工作逻辑单元。在数据库系统上执行并发操作时事务是作为最小的控制单元来使用的。这特别适用于多用户同时操作的数据通信系统。例如:订票、银行、保险公司以及证券交易系统等。
二、事务属性
事务4大属性:
1&& 原子性(Atomicity):事务是一个完整的操作。
2&& 一致性(Consistency):当事务完成时,数据必须处于一致状态。
3&& 隔离性(Isolation):对数据进行修改的所有并发事务是彼此隔离的。
4&& 持久性(Durability):事务完成后,它对于系统的影响是永久性的。
三、创建事务
T-SQL中管理事务的语句:
1 开始事务: begin transaction
2 提交事务:commit transaction
3 回滚事务: rollback transaction
1 显式事务:用begin transaction明确指定事务的开始。
2 隐性事务:打开隐性事务:set implicit_transactions on,当以隐性事务模式操作时,SQL Servler将在提交或回滚事务后自动启动新事务。无法描述事务的开始,只需要提交或回滚事务。
3 自动提交事务:SQL Server的默认模式,它将每条单独的T-SQL语句视为一个事务。如果成功执行,则自动提交,否则回滚。
在Ibatis中使用事务
public string UpdateContactPerson(string cpid)
Mapper().BeginTransaction();
Mapper().Update(&UpdateContactPerson&, cpid);
Mapper().CommitTransaction();
return &&;
catch(SqlException e)
return &&;
Mapper().RollBackTransaction();
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:349585次
积分:4474
积分:4474
排名:第4371名
原创:56篇
转载:260篇
评论:70条
(1)(3)(1)(7)(4)(13)(7)(3)(31)(9)(10)(27)(2)(7)(24)(31)(58)(22)(2)(1)(8)(2)(9)(15)(8)(8)(1)(2)&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!IBM Bluemix
点击按钮,开始云上的开发!
developerWorks 社区
本文是“”系列文章的第 3 部分,作者将继续深入剖析在实际 Spring 事务管理应用中容易遇见的一些难点,包括在使用 Spring JDBC 时如果直接获取 Connection,哪些情况会造成数据连接的泄漏与如何应对,以及除 Spring JDBC 外,其它数据访问技术数据连接泄漏的应对方案。
, 系统架构师
陈雄华,2002 年毕业于厦门大学计算机与信息工程学院,获硕士学位。拥有 10 多年的 Java 开发、设计、架构的经验。技术研发之余,常将经验所得行诸于文字,作者是国内多个著名技术网站的专栏作者,在各大技术网站、报刊杂志发表过数十篇技术文章,广受读者好评。于 2005 年出版《精通 JBuilder 2005》,于 2007 年出版《精通 Spring 2.x -- 企业应用开发详解》。
概述对于应用开发者来说,数据连接泄漏无疑是一个可怕的梦魇。如果存在数据连接泄漏问题,应用程序将因数据连接资源的耗尽而崩溃,甚至还可能引起数据库的崩溃。数据连接泄漏像黑洞一样让开发者避之唯恐不及。Spring DAO 对所有支持的数据访问技术框架都使用模板化技术进行了薄层的封装。只要您的程序都使用 Spring DAO 模板(如 JdbcTemplate、HibernateTemplate 等)进行数据访问,一定不会存在数据连接泄漏的问题 ―― 这是 Spring 给予我们郑重的承诺!因此,我们无需关注数据连接(Connection)及其衍生品(Hibernate 的 Session 等)的获取和释放的操作,模板类已经通过其内部流程替我们完成了,且对开发者是透明的。但是由于集成第三方产品,整合遗产代码等原因,可能需要直接访问数据源或直接获取数据连接及其衍生品。这时,如果使用不当,就可能在无意中创造出一个魔鬼般的连接泄漏问题。我们知道:当 Spring 事务方法运行时,就产生一个事务上下文,该上下文在本事务执行线程中针对同一个数据源绑定了一个唯一的数据连接(或其衍生品),所有被该事务上下文传播的方法都共享这个数据连接。这个数据连接从数据源获取及返回给数据源都在 Spring 掌控之中,不会发生问题。如果在需要数据连接时,能够获取这个被 Spring 管控的数据连接,则使用者可以放心使用,无需关注连接释放的问题。那么,如何获取这些被 Spring 管控的数据连接呢? Spring 提供了两种方法:其一是使用数据资源获取工具类,其二是对数据源(或其衍生品如 Hibernate SessionFactory)进行代理。在具体介绍这些方法之前,让我们先来看一下各种引发数据连接泄漏的场景。
Spring JDBC 数据连接泄漏如果直接从数据源获取连接,且在使用完成后不主动归还给数据源(调用 Connection#close()),则将造成数据连接泄漏的问题。一个具体的实例下面,来看一个具体的实例:清单 1.JdbcUserService.java:主体代码package user.
import mons.dbcp.BasicDataS
import org.springframework.beans.factory.annotation.A
import org.springframework.context.ApplicationC
import org.springframework.context.support.ClassPathXmlApplicationC
import org.springframework.jdbc.core.JdbcT
import org.springframework.stereotype.S
import java.sql.C
@Service("jdbcUserService")
public class JdbcUserService {
@Autowired
private JdbcTemplate jdbcT
public void logon(String userName) {
// ①直接从数据源获取连接,后续程序没有显式释放该连接
Connection conn = jdbcTemplate.getDataSource().getConnection();
String sql = "UPDATE t_user SET last_logon_time=? WHERE user_name =?";
jdbcTemplate.update(sql, System.currentTimeMillis(), userName);
Thread.sleep(1000);// ②模拟程序代码的执行时间
} catch (Exception e) {
e.printStackTrace();
}JdbcUserService 通过 Spring AOP 事务增强的配置,让所有 public 方法都工作在事务环境中。即让 logon() 和 updateLastLogonTime() 方法拥有事务功能。在 logon() 方法内部,我们在①处通过调用 jdbcTemplate.getDataSource().getConnection()显式获取一个连接,这个连接不是 logon() 方法事务上下文线程绑定的连接,所以如果开发者如果没有手工释放这连接(显式调用 Connection#close() 方法),则这个连接将永久被占用(处于 active 状态),造成连接泄漏!下面,我们编写模拟运行的代码,查看方法执行对数据连接的实际占用情况:清单 2.JdbcUserService.java:模拟运行代码…
@Service("jdbcUserService")
public class JdbcUserService {
//①以异步线程的方式执行JdbcUserService#logon()方法,以模拟多线程的环境
public static void asynchrLogon(JdbcUserService userService, String userName) {
UserServiceRunner runner = new UserServiceRunner(userService, userName);
runner.start();
private static class UserServiceRunner extends Thread {
private JdbcUserService userS
private String userN
public UserServiceRunner(JdbcUserService userService, String userName) {
this.userService = userS
this.userName = userN
public void run() {
userService.logon(userName);
//② 让主执行线程睡眠一段指定的时间
public static void sleep(long time) {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
//③ 汇报数据源的连接占用情况
public static void reportConn(BasicDataSource basicDataSource) {
System.out.println("连接数[active:idle]-[" +
basicDataSource.getNumActive()+":"+basicDataSource.getNumIdle()+"]");
public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext("user/connleak/applicatonContext.xml");
JdbcUserService userService = (JdbcUserService) ctx.getBean("jdbcUserService");
BasicDataSource basicDataSource = (BasicDataSource) ctx.getBean("dataSource");
//④汇报数据源初始连接占用情况
JdbcUserService.reportConn(basicDataSource);
JdbcUserService.asynchrLogon(userService, "tom");
JdbcUserService.sleep(500);
//⑤此时线程A正在执行JdbcUserService#logon()方法
JdbcUserService.reportConn(basicDataSource);
JdbcUserService.sleep(2000);
//⑥此时线程A所执行的JdbcUserService#logon()方法已经执行完毕
JdbcUserService.reportConn(basicDataSource);
JdbcUserService.asynchrLogon(userService, "john");
JdbcUserService.sleep(500);
//⑦此时线程B正在执行JdbcUserService#logon()方法
JdbcUserService.reportConn(basicDataSource);
JdbcUserService.sleep(2000);
//⑧此时线程A和B都已完成JdbcUserService#logon()方法的执行
JdbcUserService.reportConn(basicDataSource);
}在 JdbcUserService 中添加一个可异步执行 logon() 方法的 asynchrLogon() 方法,我们通过异步执行 logon() 以及让主线程睡眠的方式模拟多线程环境下的执行场景。在不同的执行点,通过 reportConn() 方法汇报数据源连接的占用情况。使用如下的 Spring 配置文件对 JdbcUserServie 的方法进行事务增强:清单 3.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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"&
&context:component-scan base-package="user.connleak"/&
&bean id="dataSource"
class="mons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="oracle.jdbc.driver.OracleDriver"
p:url="jdbc:oracle:thin:@localhost:1521:orcl"
p:username="test"
p:password="test"
p:defaultAutoCommit="false"/&
&bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource"/&
&bean id="jdbcManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/&
&!-- 对JdbcUserService的所有方法实施事务增强 --&
&aop:config proxy-target-class="true"&
&aop:pointcut id="serviceJdbcMethod"
expression="within(user.connleak.JdbcUserService+)"/&
&aop:advisor pointcut-ref="serviceJdbcMethod"
advice-ref="jdbcAdvice" order="0"/&
&/aop:config&
&tx:advice id="jdbcAdvice" transaction-manager="jdbcManager"&
&tx:attributes&
&tx:method name="*"/&
&/tx:attributes&
&/tx:advice&
&/beans&保证 BasicDataSource 数据源的配置默认连接为 0,运行以上程序代码,在控制台中将输出以下的信息:清单 4. 输出日志连接数 [active:idle]-[0:0]
连接数 [active:idle]-[2:0]
连接数 [active:idle]-[1:1]
连接数 [active:idle]-[3:0]
连接数 [active:idle]-[2:1] 我们通过下表对数据源连接的占用和泄漏情况进行描述:表 1. 执行过程数据源连接占用情况时间执行线程 1执行线程 2数据源连接activeidleleakT0
正在执行方法
正式执行方法
可见在执行线程 1 执行完毕后,只释放了一个数据连接,还有一个数据连处于 active 状态,说明泄漏了一个连接。相似的,执行线程 2 执行完毕后,也泄漏了一个连接:原因是直接通过数据源获取连接(jdbcTemplate.getDataSource().getConnection())而没有显式释放造成的。通过 DataSourceUtils 获取数据连接Spring 提供了一个能从当前事务上下文中获取绑定的数据连接的工具类,那就是 DataSourceUtils。Spring 强调必须使用 DataSourceUtils 工具类获取数据连接,Spring 的 JdbcTemplate 内部也是通过 DataSourceUtils 来获取连接的。DataSourceUtils 提供了若干获取和释放数据连接的静态方法,说明如下:static Connection doGetConnection(DataSource dataSource):首先尝试从事务上下文中获取连接,失败后再从数据源获取连接;static Connection getConnection(DataSource dataSource):和 doGetConnection 方法的功能一样,实际上,它内部就是调用 doGetConnection 方法获取连接的;static void doReleaseConnection(Connection con, DataSource dataSource):释放连接,放回到连接池中;static void releaseConnection(Connection con, DataSource dataSource):和 doReleaseConnection 方法的功能一样,实际上,它内部就是调用 doReleaseConnection 方法获取连接的;来看一下 DataSourceUtils 从数据源获取连接的关键代码:清单 5. DataSourceUtils.java 获取连接的工具类public abstract class DataSourceUtils {
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
//①首先尝试从事务同步管理器中获取数据连接
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && (conHolder.hasConnection() ||
conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug(
"Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(dataSource.getConnection());
return conHolder.getConnection();
//②如果获取不到,则直接从数据源中获取连接
Connection con = dataSource.getConnection();
//③如果拥有事务上下文,则将连接绑定到事务上下文中
if (TransactionSynchronizationManager.isSynchronizationActive()) {
ConnectionHolder holderToUse = conH
if (holderToUse == null) {
holderToUse = new ConnectionHolder(con);
else {holderToUse.setConnection(con);}
holderToUse.requested();
TransactionSynchronizationManager.registerSynchronization(
new ConnectionSynchronization(holderToUse, dataSource));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != conHolder) {
TransactionSynchronizationManager.bindResource(
dataSource, holderToUse);
}它首先查看当前是否存在事务管理上下文,并尝试从事务管理上下文获取连接,如果获取失败,直接从数据源中获取连接。在获取连接后,如果当前拥有事务上下文,则将连接绑定到事务上下文中。我们在清单 1 的 JdbcUserService 中,使用 DataSourceUtils.getConnection() 替换直接从数据源中获取连接的代码:清单 6. JdbcUserService.java:使用 DataSourceUtils 获取数据连接public void logon(String userName) {
//Connection conn = jdbcTemplate.getDataSource().getConnection();
//①使用DataSourceUtils获取数据连接
Connection conn = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
String sql = "UPDATE t_user SET last_logon_time=? WHERE user_name =?";
jdbcTemplate.update(sql, System.currentTimeMillis(), userName);
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
重新运行代码,得到如下的执行结果:清单 7. 输出日志连接数 [active:idle]-[0:0]
连接数 [active:idle]-[1:0]
连接数 [active:idle]-[0:1]
连接数 [active:idle]-[1:0]
连接数 [active:idle]-[0:1]
对照清单 4 的输出日志,我们可以看到已经没有连接泄漏的现象了。一个执行线程在运行 JdbcUserService#logon() 方法时,只占用一个连接,而且方法执行完毕后,该连接马上释放。这说明通过 DataSourceUtils.getConnection() 方法确实获取了方法所在事务上下文绑定的那个连接,而不是像原来那样从数据源中获取一个新的连接。使用 DataSourceUtils 获取数据连接也可能造成泄漏!
是否使用 DataSourceUtils 获取数据连接就可以高枕无忧了呢?理想很美好,但现实很残酷:如果 DataSourceUtils 在没有事务上下文的方法中使用 getConnection() 获取连接,依然会造成数据连接泄漏!
保持代码清单 6 的代码不变,调整 Spring 配置文件,将清单 3 中 Spring AOP 事务增强配置的代码注释掉,重新运行清单 6 的代码,将得到如下的输出日志:清单 8. 输出日志连接数 [active:idle]-[0:0]
连接数 [active:idle]-[1:1]
连接数 [active:idle]-[1:1]
连接数 [active:idle]-[2:1]
连接数 [active:idle]-[2:1]我们通过下表对数据源连接的占用和泄漏情况进行描述:表 2. 执行过程数据源连接占用情况时间执行线程 1执行线程 2数据源连接activeidleleak
正在执行方法
正式执行方法
仔细对照表 1 的执行过程,我们发现在 T1 时,有事务上下文时的 active 为 2,idle 为 0,而此时由于没有事务管理,则 active 为 1 而 idle 也为 1。这说明有事务上下文时,需要等到整个事务方法(即 logon())返回后,事务上下文绑定的连接才释放。但在没有事务上下文时,logon() 调用 JdbcTemplate 执行完数据操作后,马上就释放连接。在 T2 执行线程完成 logon() 方法的执行后,有一个连接没有被释放(active),所以发生了连接泄漏。到 T4 时,两个执行线程都完成了 logon() 方法的调用,但是出现了两个未释放的连接。要堵上这个连接泄漏的漏洞,需要对 logon() 方法进行如下的改造:清单 9.JdbcUserService.java:手工释放获取的连接public void logon(String userName) {
Connection conn =
conn = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
String sql = "UPDATE t_user SET last_logon_time=? WHERE user_name =?";
jdbcTemplate.update(sql, System.currentTimeMillis(), userName);
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}finally {
// ②显式使用DataSourceUtils释放连接
DataSourceUtils.releaseConnection(conn,jdbcTemplate.getDataSource());
}在 ② 处显式调用 DataSourceUtils.releaseConnection() 方法释放获取的连接。特别需要指出的是:一定不能在 ① 处释放连接!因为如果 logon() 在获取连接后,①
处代码前这段代码执行时发生异常,则①处释放连接的动作将得不到执行。这将是一个非常具有隐蔽性的连接泄漏的隐患点。JdbcTemplate 如何做到对连接泄漏的免疫分析 JdbcTemplate 的代码,我们可以清楚地看到它开放的每个数据操作方法,首先都使用 DataSourceUtils 获取连接,在方法返回之前使用 DataSourceUtils 释放连接。
来看一下 JdbcTemplate 最核心的一个数据操作方法 execute():清单 10.JdbcTemplate#execute()public &T& T execute(StatementCallback&T& action) throws DataAccessException {
//① 首先根据DataSourceUtils获取数据连接
Connection con = DataSourceUtils.getConnection(getDataSource());
Statement stmt =
Connection conToUse =
handleWarnings(stmt);
catch (SQLException ex) {
JdbcUtils.closeStatement(stmt);
DataSourceUtils.releaseConnection(con, getDataSource());
throw getExceptionTranslator().translate(
"StatementCallback", getSql(action), ex);
JdbcUtils.closeStatement(stmt);
//② 最后根据DataSourceUtils释放数据连接
DataSourceUtils.releaseConnection(con, getDataSource());
}在 ① 处通过 DataSourceUtils.getConnection() 获取连接,在 ② 处通过 DataSourceUtils.releaseConnection() 释放连接。所有 JdbcTemplate 开放的数据访问方法最终都是通过 execute(StatementCallback&T& action)执行数据访问操作的,因此这个方法代表了 JdbcTemplate 数据操作的最终实现方式。正是因为 JdbcTemplate 严谨的获取连接,释放连接的模式化流程保证了 JdbcTemplate 对数据连接泄漏问题的免疫性。所以,如有可能尽量使用 JdbcTemplate,HibernateTemplate 等这些模板进行数据访问操作,避免直接获取数据连接的操作。使用 TransactionAwareDataSourceProxy如果不得已要显式获取数据连接,除了使用 DataSourceUtils 获取事务上下文绑定的连接外,还可以通过 TransactionAwareDataSourceProxy 对数据源进行代理。数据源对象被代理后就具有了事务上下文感知的能力,通过代理数据源的 getConnection() 方法获取的连接和使用 DataSourceUtils.getConnection() 获取连接的效果是一样的。下面是使用 TransactionAwareDataSourceProxy 对数据源进行代理的配置:清单 11.applicationContext.xml:对数据源进行代理&bean id="dataSource"
class="mons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="oracle.jdbc.driver.OracleDriver"
p:url="jdbc:oracle:thin:@localhost:1521:orcl"
p:username="test"
p:password="test"
p:defaultAutoCommit="false"/&
&!-- ①对数据源进行代理--&
&bean id="dataSourceProxy"
class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy"
p:targetDataSource-ref="dataSource"/&
&!-- ②直接使用数据源的代理对象--&
&bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSourceProxy"/&
&!-- ③直接使用数据源的代理对象--&
&bean id="jdbcManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSourceProxy"/&对数据源进行代理后,我们就可以通过数据源代理对象的 getConnection() 获取事务上下文中绑定的数据连接了。因此,如果数据源已经进行了 TransactionAwareDataSourceProxy 的代理,而且方法存在事务上下文,那么清单 1 的代码也不会生产连接泄漏的问题。其它数据访问技术的等价类理解了 Spring JDBC 的数据连接泄漏问题,其中的道理可以平滑地推广到其它框架中去。Spring 为每个数据访问技术框架都提供了一个获取事务上下文绑定的数据连接(或其衍生品)的工具类和数据源(或其衍生品)的代理类。DataSourceUtils 的等价类下表列出了不同数据访问技术对应 DataSourceUtils 的等价类:表 3. 不同数据访问框架 DataSourceUtils 的等价类数据访问技术框架连接 ( 或衍生品 ) 获取工具类
Spring JDBC
org.springframework.jdbc.datasource.DataSourceUtils
org.springframework.orm.hibernate3.SessionFactoryUtils
org.springframework.jdbc.datasource.DataSourceUtils
org.springframework.orm.jpa.EntityManagerFactoryUtils
org.springframework.orm.jdo.PersistenceManagerFactoryUtils
TransactionAwareDataSourceProxy 的等价类下表列出了不同数据访问技术框架下 TransactionAwareDataSourceProxy 的等价类:表 4. 不同数据访问框架 TransactionAwareDataSourceProxy 的等价类数据访问技术框架连接 ( 或衍生品 ) 获取工具类
Spring JDBC
org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
org.springframework.orm.hibernate3.LocalSessionFactoryBean
org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy
小结在本文中,我们通过剖析了解到以下的真相:使用 Spring JDBC 时如果直接获取 Connection,可能会造成连接泄漏。为降低连接泄漏的可能,尽量使用 DataSourceUtils 获取数据连接。也可以对数据源进行代理,以便将其拥有事务上下文的感知能力;可以将 Spring JDBC 防止连接泄漏的解决方案平滑应用到其它的数据访问技术框架中。
参考 ,您可以了解更多需要强调的内容。
“”(developerWorks,2009 年 1 月):本教程从基础知识开始,详细分析了 Spring 事务管理的使用方法,为读者理清思路。“”(developerWorks,2007 年 2 月):讲述了一些基础知识,包括什么是事务,以及事务对于构建可靠 的分布式应用程序来说至关重要的原因。“”(developerWorks,2009 年 3 月):该系列文章通过使用 Spring Framework 和企业 EJB 3.0 规范中的代码示例解释了这些极其常见的错误。“”(developerWorks,2005 年 8 月):开始学习如何用 Spring 技术构建轻量级的、强壮的 J2EE 应用程序。“”(developerWorks,2008 年 2 月):本文通过实例详细讲述了 Spring 2.5 基于注释 IoC 功能的使用。“”(developerWorks,2008 年 3 月):本文将介绍 Spring 2.5 新增的 Sping MVC 注解功能,讲述如何使用注解配置替换传统的基于 XML 的 Spring MVC 配置。:浏览关于这些和其他技术主题的图书。:数百篇关于 Java 编程各个方面的文章。加入 。查看 的最新信息。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
文章、教程、演示,帮助您构建、部署和管理云应用。
立即加入来自 IBM 的专业 IT 社交网络。
为灾难恢复构建应用,赢取现金大奖。
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=Java technology, Open sourceArticleID=478038ArticleTitle=Spring 事务管理高级应用难点剖析: 第 3 部分publish-date=

我要回帖

更多关于 ibatis 的文章

 

随机推荐