/*
* Copyright 2010-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mybatis.spring;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.fail;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.apache.ibatis.transaction.managed.ManagedTransactionFactory;
import org.junit.After;
import org.junit.Test;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.TransientDataAccessResourceException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import com.mockrunner.mock.ejb.MockUserTransaction;
import com.mockrunner.mock.jdbc.MockConnection;
import com.mockrunner.mock.jdbc.MockDataSource;
import com.mockrunner.mock.jdbc.MockPreparedStatement;
/**
* @version $Id$
*/
public final class MyBatisSpringTest extends AbstractMyBatisSpringTest {
private SqlSession session;
@After
public void validateSessionClose() {
// assume if the Executor is closed, the Session is too
if ((session != null) && !executorInterceptor.isExecutorClosed()) {
session = null;
fail("SqlSession is not closed");
} else {
session = null;
}
}
// ensure MyBatis API still works with SpringManagedTransaction
@Test
public void testMyBatisAPI() {
session = sqlSessionFactory.openSession();
session.getMapper(TestMapper.class).findTest();
session.close();
assertNoCommit();
assertSingleConnection();
assertExecuteCount(1);
}
@Test
public void testMyBatisAPIWithCommit() {
session = sqlSessionFactory.openSession();
session.getMapper(TestMapper.class).findTest();
session.commit(true);
session.close();
assertCommit();
assertSingleConnection();
assertExecuteCount(1);
}
@Test
public void testMyBatisAPIWithRollback() {
session = sqlSessionFactory.openSession();
session.getMapper(TestMapper.class).findTest();
session.rollback(true);
session.close();
assertRollback();
assertSingleConnection();
assertExecuteCount(1);
}
// basic tests using SqlSessionUtils instead of using the MyBatis API directly
@Test
public void testSpringAPI() {
session = SqlSessionUtils.getSqlSession(sqlSessionFactory);
session.getMapper(TestMapper.class).findTest();
SqlSessionUtils.closeSqlSession(session, sqlSessionFactory);
assertNoCommit();
assertSingleConnection();
assertExecuteCount(1);
}
@Test
public void testSpringAPIWithCommit() {
session = SqlSessionUtils.getSqlSession(sqlSessionFactory);
session.getMapper(TestMapper.class).findTest();
session.commit(true);
SqlSessionUtils.closeSqlSession(session, sqlSessionFactory);
assertCommit();
assertSingleConnection();
}
@Test
public void testSpringAPIWithRollback() {
session = SqlSessionUtils.getSqlSession(sqlSessionFactory);
session.getMapper(TestMapper.class).findTest();
session.rollback(true);
SqlSessionUtils.closeSqlSession(session, sqlSessionFactory);
assertRollback();
assertSingleConnection();
}
@Test
public void testSpringAPIWithMyBatisClose() {
// This is a programming error and could lead to connection leak if there is a transaction
// in progress. But, the API allows it, so make sure it at least works without a tx.
session = SqlSessionUtils.getSqlSession(sqlSessionFactory);
session.getMapper(TestMapper.class).findTest();
session.close();
assertNoCommit();
assertSingleConnection();
}
// Spring API should work with a MyBatis TransactionFactories
@Test
public void testWithNonSpringTransactionFactory() {
Environment original = sqlSessionFactory.getConfiguration().getEnvironment();
Environment nonSpring = new Environment("non-spring", new JdbcTransactionFactory(), dataSource);
sqlSessionFactory.getConfiguration().setEnvironment(nonSpring);
try {
session = SqlSessionUtils.getSqlSession(sqlSessionFactory);
session.getMapper(TestMapper.class).findTest();
SqlSessionUtils.closeSqlSession(session, sqlSessionFactory);
// users need to manually call commit, rollback and close, just like with normal MyBatis
// API usage
assertNoCommit();
assertSingleConnection();
} finally {
sqlSessionFactory.getConfiguration().setEnvironment(original);
}
}
// Spring TX, non-Spring TransactionFactory, Spring managed DataSource
// this should not work since the DS will be out of sync with MyBatis
@Test(expected = TransientDataAccessResourceException.class)
public void testNonSpringTxFactoryWithTx() throws Exception {
Environment original = sqlSessionFactory.getConfiguration().getEnvironment();
Environment nonSpring = new Environment("non-spring", new JdbcTransactionFactory(), dataSource);
sqlSessionFactory.getConfiguration().setEnvironment(nonSpring);
TransactionStatus status = null;
try {
status = txManager.getTransaction(new DefaultTransactionDefinition());
session = SqlSessionUtils.getSqlSession(sqlSessionFactory);
fail("should not be able to get an SqlSession using non-Spring tx manager when there is an active Spring tx");
} finally {
// rollback required to close connection
txManager.rollback(status);
sqlSessionFactory.getConfiguration().setEnvironment(original);
}
}
// Spring TX, non-Spring TransactionFactory, MyBatis managed DataSource
// this should work since the DS is managed MyBatis
@Test
public void testNonSpringTxFactoryNonSpringDSWithTx() throws java.sql.SQLException {
Environment original = sqlSessionFactory.getConfiguration().getEnvironment();
MockDataSource mockDataSource = new MockDataSource();
mockDataSource.setupConnection(createMockConnection());
Environment nonSpring = new Environment("non-spring", new JdbcTransactionFactory(), mockDataSource);
sqlSessionFactory.getConfiguration().setEnvironment(nonSpring);
TransactionStatus status = null;
try {
status = txManager.getTransaction(new DefaultTransactionDefinition());
session = SqlSessionUtils.getSqlSession(sqlSessionFactory);
session.commit();
session.close();
txManager.commit(status);
// txManager still uses original connection
assertCommit();
assertSingleConnection();
// SqlSession uses its own connection
// that connection will not have commited since no SQL was executed by the session
MockConnection mockConnection = (MockConnection) mockDataSource.getConnection();
assertEquals("should call commit on Connection", 0, mockConnection.getNumberCommits());
assertEquals("should not call rollback on Connection", 0, mockConnection.getNumberRollbacks());
assertCommitSession();
} finally {
SqlSessionUtils.closeSqlSession(session, sqlSessionFactory);
sqlSessionFactory.getConfiguration().setEnvironment(original);
}
}
@Test(expected = TransientDataAccessResourceException.class)
public void testChangeExecutorT
spring-mybatis-spring-1.2.1.zip
需积分: 0 141 浏览量
更新于2024-04-19
收藏 298KB ZIP 举报
《Spring与MyBatis整合详解》
在Java开发领域,Spring框架以其强大的功能和灵活性,成为了企业级应用的首选。而MyBatis作为一款轻量级的持久层框架,以其简单易用、灵活的SQL映射深受开发者喜爱。将两者进行整合,可以充分利用Spring的依赖注入和事务管理能力,以及MyBatis的SQL定制化特性,提升项目的开发效率和可维护性。本文将详细介绍如何在Windows环境下,免费下载并整合Spring与MyBatis。
"spring-mybatis-spring-1.2.1.zip"是一个包含整合资源的压缩包,其主要目的是提供Spring与MyBatis整合所需的文件,适用于Windows各版本。在下载这个资源包后,解压得到的文件将包括Spring和MyBatis的相关配置、库文件以及示例代码等,为开发者提供了一站式的整合方案。
1. **Spring与MyBatis整合基础**
- **Spring**:Spring是一个全面的企业级应用框架,它提供了IOC(Inversion of Control)和AOP(Aspect Oriented Programming)等核心特性,简化了Java应用的开发和管理。
- **MyBatis**:MyBatis是一个基于Java的持久层框架,它允许开发者编写自由的SQL,将SQL语句与Java代码分离,提高了数据库操作的灵活性。
2. **整合步骤**
- **配置Spring**:在Spring的配置文件(如`applicationContext.xml`)中,需要定义数据源、SqlSessionFactoryBean以及MyBatis的MapperScannerConfigurer,后者用于扫描项目中的Mapper接口。
- **配置MyBatis**:在MyBatis的主配置文件(`mybatis-config.xml`)中,设置数据源、事务管理器等相关配置。
- **Mapper接口与XML映射文件**:创建Mapper接口,每个方法对应一个SQL语句,XML映射文件则定义具体的SQL和结果映射。
- **Spring的事务管理**:通过Spring的PlatformTransactionManager接口,可以实现声明式事务管理,无需在业务代码中显式处理事务。
3. **示例代码解析**
- **SqlSessionFactoryBean**:配置Spring的SqlSessionFactoryBean,用于创建SqlSessionFactory实例,它是MyBatis的核心对象。
```xml
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 配置MyBatis的配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml" />
</bean>
```
- **MapperScannerConfigurer**:扫描项目中的Mapper接口,自动加载到Spring容器。
```xml
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.mapper" /> <!-- Mapper接口所在包名 -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>
```
4. **实际应用**
- **Service层**:在Service层中,通过@Autowired注解注入Mapper接口,Spring会自动根据接口创建对应的Mapper实例。
```java
@Autowired
private UserMapper userMapper;
```
- **事务控制**:在需要进行事务操作的方法上添加@Transactional注解,Spring会自动管理事务的开始、提交或回滚。
5. **优化与最佳实践**
- **Mapper的动态代理**:为了进一步简化调用,可以使用MyBatis的MapperFactoryBean生成Mapper的代理对象,避免使用@Autowired直接注入Mapper接口。
- **SQL性能优化**:合理设计SQL,避免全表扫描,利用索引提高查询效率。
- **日志配置**:开启MyBatis的日志,便于调试和优化SQL。
通过以上步骤,我们可以轻松地在Windows环境下,免费下载并整合Spring与MyBatis,构建起高效、灵活的持久层架构。这不仅可以提高开发效率,也能降低项目的维护成本。在实际项目中,开发者可以根据具体需求进行调整和优化,以实现更符合项目特性的解决方案。