整合Spring3及MyBatis3 (转载)
对于整合Spring及Mybatis不作详细介绍,可以参考: MyBatis 3 User Guide Simplified Chinese.pdf,贴出我的主要代码如下:
UserMapper Interface:
package org.denger.mapper;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.annotations.Select;import org.denger.po.User;public interface UserMapper {@Select("select * from tab_uc_account where id=#{userId}")User getUser(@Param("userId") Long userId);}
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://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-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"><!-- Provided by annotation-based configuration --><context:annotation-config/><!--JDBC Transaction Manage --><bean id="dataSourceProxy" /></constructor-arg></bean><!-- The JDBC c3p0 dataSource bean--><bean id="dataSource" destroy-method="close"><property name="driverClass" value="com.mysql.jdbc.Driver" /><property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/noah" /><property name="user" value="root" /><property name="password" value="123456" /></bean><!--MyBatis integration with Spring as define sqlSessionFactory --><bean id="sqlSessionFactory" ref="dataSource" /></bean><bean ref="sqlSessionFactory"/><property name="basePackage" value="org.denger.mapper"></property></bean></beans>
package org.denger.mapper;import org.junit.Assert;import org.junit.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;@ContextConfiguration(locations = { "/application-context.xml"})public class UserMapperTest extends AbstractJUnit4SpringContextTests{@Autowiredpublic UserMapper userMapper;@Testpublic void testGetUser(){Assert.assertNotNull(userMapper.getUser(300L));}}
<bean ref="sqlSessionFactory"/><property name="basePackage" value="org.denger.mapper"></property></bean>
/*** Calls the parent search that will search and register all the candidates. Then the* registered objects are post processed to set them as MapperFactoryBeans*/@Overrideprotected Set<BeanDefinitionHolder> doScan(String... basePackages) { //#1Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);if (beanDefinitions.isEmpty()) { logger.warn("No MyBatis mapper was found in '" + MapperScannerConfigurer.this.basePackage + "' package. Please check your configuration.");} else { //#2 for (BeanDefinitionHolder holder : beanDefinitions) { GenericBeanDefinition definition = (GenericBeanDefinition) holder.getBeanDefinition();if (logger.isDebugEnabled()) {logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '"+ definition.getBeanClassName() + "' mapperInterface");} //#3 definition.getPropertyValues().add("mapperInterface", definition.getBeanClassName()); definition.setBeanClass(MapperFactoryBean.class); }return beanDefinitions;}
/** * {@inheritDoc} */ public void afterPropertiesSet() throws Exception { Assert.notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required"); Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required"); Configuration configuration = this.sqlSession.getConfiguration(); if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) { configuration.addMapper(this.mapperInterface); } }
/** * {@inheritDoc} */ public T getObject() throws Exception { return this.sqlSession.getMapper(this.mapperInterface); }
/** * {@inheritDoc} */ public <T> T getMapper(Class<T> type) { return getConfiguration().getMapper(type, this); }
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); }
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { //首先判断当前knownMappers是否存在mapper interface class.因为前面说到 afterPropertiesSet 中已经将当前的 mapperinterfaceclass 添加进入了。 if (!knownMappers.contains(type)) throw new BindingException("Type " + type + " is not known to the MapperRegistry."); try { return MapperProxy.newMapperProxy(type, sqlSession); } catch (Exception e) { throw new BindingException("Error getting mapper instance. Cause: " + e, e); } }
public static <T> T newMapperProxy(Class<T> mapperInterface, SqlSession sqlSession) { ClassLoader classLoader = mapperInterface.getClassLoader(); Class[] interfaces = new Class[]{mapperInterface}; MapperProxy proxy = new MapperProxy(sqlSession); return (T) Proxy.newProxyInstance(classLoader, interfaces, proxy); }
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { //如果调用不是 object 中默认的方法(如equals之类的) if (!OBJECT_METHODS.contains(method.getName())) { //因为当前MapperProxy代理了所有 Mapper,所以他需要根据当前拦截到的方法及代理对象获取 MapperInterface class,也就是我这里的 UserMapper.class final Class declaringInterface = findDeclaringInterface(proxy, method); //然后再根据UserMapper.class、及当前调用的Method(也就是getUser)及SqlSession构造一个 MapperMethod,在这里面会获取到 getUser方法上的 @Select() 的SQL,然后再通过 sqlSession来进行执行 final MapperMethod mapperMethod = new MapperMethod(declaringInterface, method, sqlSession); //execute执行数据库操作,并返回结果集 final Object result = mapperMethod.execute(args); if (result == null && method.getReturnType().isPrimitive()) { throw new BindingException("Mapper method '" + method.getName() + "' (" + method.getDeclaringClass() + ") attempted to return null from a method with a primitive return type (" + method.getReturnType() + ")."); } return result; } } catch (SQLException e) { e.printStackTrace(); } return null; }