- 浏览: 448835 次
- 性别:
- 来自: 杭州
-
文章分类
- 全部博客 (162)
- easymock (3)
- 模板引擎 (3)
- JForum (4)
- web (9)
- spring (10)
- java (20)
- struts (9)
- uml (3)
- java pattern (19)
- JQuery (14)
- 多线程 (13)
- database (21)
- PS (3)
- ejb (6)
- 版本管理 svn , maven , ant (2)
- protocol (1)
- 测试 (1)
- ws (7)
- Apache (4)
- 脚本语言 (1)
- guice (1)
- 分布式 (4)
- 架构 (0)
- 经验 (1)
- 版本管理 svn (1)
- maven (1)
- ant (1)
- 书籍 (1)
- Linux (1)
最新评论
-
Master-Gao:
稍微明白了点,,有点萌萌哒
为什么匿名内部类参数必须为final类型 -
waw0931:
终于明白了,谢谢!
为什么匿名内部类参数必须为final类型 -
十三圆桌骑士:
提供了两个链接还是有用的。
安装Mondrian -
放方芳:
[flash=200,200][/flash]
Freemarker标签使用 -
放方芳:
[b][/b]
Freemarker标签使用
整合Spring3及MyBatis3
对于整合Spring及Mybatis不作详细介绍,可以参考: MyBatis 3 User Guide Simplified Chinese.pdf,贴出我的主要代码如下:
UserMapper Interface:
application-context.xml:
test Class:
实现原理分析
对于以上极其简单代码看上去并无特殊之处,主要亮点在于 UserMapper 居然不用实现类,而且在调用 getUser 的时候,也是使用直接调用了UserMapper实现类,那么Mybatis是如何去实现 UserMapper的接口的呢?
可能你马上能想到的实现机制就是通过动态代理方式,好吧,看看MyBatis整个的代理过程吧。
首先在Spring的配置文件中看到下面的Bean:
以上的MapperScannerConfigurer class的注释中描述道:
从base 包中搜索所有下面所有 interface,并将其注册到 Spring Bean容器中,其注册的class bean是MapperFactoryBean。
好吧,看看它的注册过程,下面方法来从 MapperScannerConfigurer中的Scanner类中抽取,下面方法在初始化以上application-content.xml文件时就会进行调用。 主要用于是搜索 base packages 下的所有mapper class,并将其注册至 spring 的 benfinitionHolder中。
#2: 首先,由于 #1: 中注册的都是接口class, 可以肯定的是接口是不能直接初始化的;实际 #2: 中for循环中替换当前所有 holder的 className为 MapperFactoryBean.class,并且将 mapper interface的class name setter 至 MapperFactoryBean 属性为 mapperInterface 中,也就是 #3: 代码所看到的。
再看看 MapperFactoryBean,它是直接实现了 Spring 的 FactoryBean及InitializingBean 接口。其实既使不看这两个接口,当看MapperFactoryBean的classname就知道它是一个专门用于创建 Mapper 实例Bean的工厂。
至此,已经完成了Spring与mybatis的整合的初始化配置的过程。
接着,当我在以上的 Test类中,需要注入 UserMapper接口实例时,由于mybatis给所有的Mapper 实例注册都是一个MapperFactory的工厂,所以产生UserMapper实现仍需要 MapperFactoryBean来进行创建。接下来看看 MapperFactoryBean的处理过程。
先需要创建Mapper实例时,首先在 MapperFactoryBean中执行的方法是:

到目前为止我们的 UserMapper实例实际上还并未产生; 再进入org.mybatis.spring.SqlSessionTemplate中的getMapper方法,该方法将 this及mapper interface class 作为参数传入 org.apache.ibatis.session.Configuration的getMapper() 方法中,代码如下:
于是,再进入 org.apache.ibatis.session.Configuration.getMapper中代码如下:
再进入 org.apache.ibatis.binding.MapperRegistry.getMapper方法,代码如下:
嗯,没错,看到 MapperProxy.newMapperProxy后可以肯定的是它确实采用的代理模式,再进入一看究竟吧:
JDK的动态代理就不说了,至此,基本Mybatis已经完成了Mapper实例的整个创建过程,也就是你在具体使用 UserMapper.getUser 时,它实际上调用的是 MapperProxy,因为此时 所返回的 MapperProxy是实现了 UserMapper接口的。只不过 MapperProxy拦截了所有对userMapper中方法的调用,如下:
对于整合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);
- }
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); }
application-context.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: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-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" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
- <constructor-arg>
- <ref bean="dataSource" />
- </constructor-arg>
- </bean>
- <!-- The JDBC c3p0 dataSource bean-->
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" 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" class="org.mybatis.spring.SqlSessionFactoryBean">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
- <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
- <property name="basePackage" value="org.denger.mapper"></property>
- </bean>
- </beans>
<?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/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-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" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy"> <constructor-arg> <ref bean="dataSource" /> </constructor-arg> </bean> <!-- The JDBC c3p0 dataSource bean--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" 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" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> <property name="basePackage" value="org.denger.mapper"></property> </bean> </beans>
test Class:
- 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{
- @Autowired
- public UserMapper userMapper;
- @Test
- public void testGetUser(){
- Assert.assertNotNull(userMapper.getUser(300L));
- }
- }
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{ @Autowired public UserMapper userMapper; @Test public void testGetUser(){ Assert.assertNotNull(userMapper.getUser(300L)); } }
实现原理分析
对于以上极其简单代码看上去并无特殊之处,主要亮点在于 UserMapper 居然不用实现类,而且在调用 getUser 的时候,也是使用直接调用了UserMapper实现类,那么Mybatis是如何去实现 UserMapper的接口的呢?
可能你马上能想到的实现机制就是通过动态代理方式,好吧,看看MyBatis整个的代理过程吧。
首先在Spring的配置文件中看到下面的Bean:
- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
- <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
- <property name="basePackage" value="org.denger.mapper"></property>
- </bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> <property name="basePackage" value="org.denger.mapper"></property> </bean>
以上的MapperScannerConfigurer class的注释中描述道:
从base 包中搜索所有下面所有 interface,并将其注册到 Spring Bean容器中,其注册的class bean是MapperFactoryBean。
好吧,看看它的注册过程,下面方法来从 MapperScannerConfigurer中的Scanner类中抽取,下面方法在初始化以上application-content.xml文件时就会进行调用。 主要用于是搜索 base packages 下的所有mapper class,并将其注册至 spring 的 benfinitionHolder中。
- /**
- * Calls the parent search that will search and register all the candidates. Then the
- * registered objects are post processed to set them as MapperFactoryBeans
- */
- @Override
- protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
- //#1
- Set<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;
- }
/** * Calls the parent search that will search and register all the candidates. Then the * registered objects are post processed to set them as MapperFactoryBeans */ @Override protected Set<BeanDefinitionHolder> doScan(String... basePackages) { //#1 Set<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; }#1: 了解Spring初始化Bean过程的人可能都知道,Spring 首先会将需要初始化的所有class先通过BeanDefinitionRegistry进行注册,并且将该Bean的一些属性信息(如scope、className、beanName等)保存至BeanDefinitionHolder中;Mybatis这里首先会调用Spring中的ClassPathBeanDefinitionScanner.doScan方法,将所有Mapper接口的class注册至BeanDefinitionHolder实例中,然后返回一个Set<BeanDefinitionHolder>,其它包含了所有搜索到的Mapper class BeanDefinitionHolder对象。
#2: 首先,由于 #1: 中注册的都是接口class, 可以肯定的是接口是不能直接初始化的;实际 #2: 中for循环中替换当前所有 holder的 className为 MapperFactoryBean.class,并且将 mapper interface的class name setter 至 MapperFactoryBean 属性为 mapperInterface 中,也就是 #3: 代码所看到的。
再看看 MapperFactoryBean,它是直接实现了 Spring 的 FactoryBean及InitializingBean 接口。其实既使不看这两个接口,当看MapperFactoryBean的classname就知道它是一个专门用于创建 Mapper 实例Bean的工厂。
至此,已经完成了Spring与mybatis的整合的初始化配置的过程。
接着,当我在以上的 Test类中,需要注入 UserMapper接口实例时,由于mybatis给所有的Mapper 实例注册都是一个MapperFactory的工厂,所以产生UserMapper实现仍需要 MapperFactoryBean来进行创建。接下来看看 MapperFactoryBean的处理过程。
先需要创建Mapper实例时,首先在 MapperFactoryBean中执行的方法是:
- /**
- * {@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 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); } }上面方法中先会检测当前需要创建的 mapperInterface在全局的 Configuration中是否存在,如果不存在则添加。呆会再说他为什么要将 mapperInterface 添加至 Configuration中。该方法调用完成之后,就开始调用 getObject方法来产生mapper实例,看到MapperFactoryBean.getObject的该方法代码如下:
- /**
- * {@inheritDoc}
- */
- public T getObject() throws Exception {
- return this.sqlSession.getMapper(this.mapperInterface);
- }
/** * {@inheritDoc} */ public T getObject() throws Exception { return this.sqlSession.getMapper(this.mapperInterface); }通过Debug可以看到 sqlSession及mapperInterface对象:

到目前为止我们的 UserMapper实例实际上还并未产生; 再进入org.mybatis.spring.SqlSessionTemplate中的getMapper方法,该方法将 this及mapper interface class 作为参数传入 org.apache.ibatis.session.Configuration的getMapper() 方法中,代码如下:
- /**
- * {@inheritDoc}
- */
- public <T> T getMapper(Class<T> type) {
- return getConfiguration().getMapper(type, this);
- }
/** * {@inheritDoc} */ public <T> T getMapper(Class<T> type) { return getConfiguration().getMapper(type, this); }
于是,再进入 org.apache.ibatis.session.Configuration.getMapper中代码如下:
- public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
- return mapperRegistry.getMapper(type, sqlSession);
- }
public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return mapperRegistry.getMapper(type, sqlSession); }其中 mapperRegistry保存着当前所有的 mapperInterface class. 那么它在什么时候将 mapperinterface class 保存进入的呢?其实就是在上面的 afterPropertiesSet 中通过 configuration.addMapper(this.mapperInterface) 添加进入的。
再进入 org.apache.ibatis.binding.MapperRegistry.getMapper方法,代码如下:
- 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 <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); } }
嗯,没错,看到 MapperProxy.newMapperProxy后可以肯定的是它确实采用的代理模式,再进入一看究竟吧:
- 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 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); }
JDK的动态代理就不说了,至此,基本Mybatis已经完成了Mapper实例的整个创建过程,也就是你在具体使用 UserMapper.getUser 时,它实际上调用的是 MapperProxy,因为此时 所返回的 MapperProxy是实现了 UserMapper接口的。只不过 MapperProxy拦截了所有对userMapper中方法的调用,如下:
- 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;
- }
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; }为什么说它拦截了呢?可以看到, 它并没有调用 method.invoke(object)方法,因为实际上 MapperProxy只是动态的 implement 了UserMapper接口,但它没有真正实现 UserMapper中的任何方法。至于结果的返回,它也是通过 MapperMethod.execute 中进行数据库操作来返回结果的。 说白了,就是一个实现了 MapperInterface 的 MapperProxy 实例被MapperProxy代理了,可以debug看看 userMapper实例就是 MapperProxy。
发表评论
-
安装Mondrian
2014-04-11 10:48 4662Mondrian and OLAP Mondrian i ... -
NoSql 笔记
2014-02-18 17:39 773看了一些关于NoSql的文 ... -
mysql explain用法
2014-02-14 11:53 946补充一点: id 就是 sql 语句中 select 出现 ... -
数据库范式概念解析(第一范式,第二范式,第三范式)
2013-02-26 10:17 1131大部分数据库从业人员 ... -
ORACLE数据库基础知识
2013-02-23 11:39 892http://wenku.baidu.com/view/958 ... -
Oracle 的性能优化概述
2013-02-23 11:34 1077Oracle 的性能优化概 ... -
mysql 索引
2013-02-23 11:33 984索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一 ... -
hibernate规则
2012-12-18 14:58 1113实体类的编写规则 l 实体类必须具备无参 ... -
Hibernate 关联关系映射(Association Relationship Mapping)
2012-12-17 18:55 986一对一主键关联 数据表为:夫妻表 POJO 为 ... -
关系型数据库性能优化总结(转)
2012-06-13 14:17 869关系型数据库性能优化 ... -
spring+hibernate架构中Dao访问数据库的几种方法
2011-11-28 18:10 1428spring+hibernate架构中Dao访问数据库的几种方 ... -
mybatis 缓存(二)
2011-10-20 13:05 5365缓存不适合情况:select ... -
mybatis 缓存(一)
2011-10-20 11:27 1294缓存概述 http://www.iteye.com/topi ... -
mybatis 基本
2011-10-20 11:14 1489今天刚听说iBATIS改名为MyBatis,实际上就是iBAT ... -
hibernate 延迟加载(一)
2011-10-12 10:03 972首先是第一个误区:延迟加载只能作用于关联实体 看到这个是不 ... -
mybatis 多对多 处理
2011-09-26 18:41 42121下面的例子让新手看 ... -
解释 关闭statement 和rs
2010-09-19 13:14 2377很多朋友在Java开发中, ... -
HIBERNATE
2010-07-30 11:51 889使用java进行项目开发也有不少年头了,应用从网站到金融产品到 ... -
Oracle嵌套表和数组的使用(省去了连接查询)
2010-07-27 17:18 2319Oracle嵌套表的使用 1. 创建对象类型 create ... -
延迟加载
2010-07-11 14:04 1347could not initialize proxy - no ...
相关推荐
源码分析可以帮助我们了解这三大框架如何协同工作,例如,Struts2如何转发请求到Spring管理的Bean,Spring如何调用MyBatis执行SQL,以及MyBatis如何将数据库结果映射到Java对象。 【工具】在开发过程中,开发者通常...
在整合这三个技术时,通常会使用Spring的ApplicationContext来加载配置,包含MyBatis的SqlSessionFactory和Mapper接口,以及Quartz的Scheduler实例。MyBatis的配置文件中,会指定数据源、事务管理器以及Mapper文件的...
本项目"java+spring+mybatis+mysql+RuoYi-atomikos-实现分布式事务.zip"是一个基于若依(RuoYi)框架改造的多模块分布式事务解决方案,它利用了Atomikos这一强大的分布式事务管理器。以下将详细解析这个项目的知识点...
**Spring整合Mybatis原理分析** 在Java Web开发中,Spring框架以其强大的依赖注入和面向切面编程能力,成为了事实上的核心框架。Mybatis则是一个轻量级的持久层框架,它简化了数据库操作,提供了直观的SQL映射。将...
标题 "Spring+SpringMVC+Mybatis资源课件" 提供了一个学习路径,涉及Java开发中的三个关键组件:Spring框架、SpringMVC和Mybatis。这些技术是构建现代企业级Web应用程序的基础,尤其是在Java世界中。 Spring框架是...
myBatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录,使得开发者可以更加专注于业务逻辑的实现,而无需关心繁琐的数据库操作。...
通过分析和研究这个源代码,开发者可以深入理解它们的协同工作原理,以及如何在项目中实现业务逻辑、控制流程和数据访问。 描述中提到的"ruts+spring+mybatis源代码例子,留给大家参考"表明这个压缩包提供的不仅仅...
【Spring+Mybatis+LigerUI】:这是一个基于Spring、Mybatis和LigerUI构建的简单Web应用程序示例。Spring作为一个全面的Java企业级应用框架,提供了依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等核心...
在实际项目中,"TickerDemo20170614_2"可能是项目的源码包或者相关资源文件,包含着SSM框架的配置文件(如spring-servlet.xml、mybatis-config.xml)、实体类(Employee)、Mapper接口与XML映射文件、Controller类...
《二年级JAVAEE学生信息管理系统:Spring+SpringMVC+Mybatis+Mysql+Tomcat实践解析》 在信息技术日益发达的今天,信息化管理已成为各行各业不可或缺的重要组成部分。本项目——"二年级JAVAEE学生信息管理系统",...
对于学生来说,这个项目不仅能提升Java编程技能,还能了解Springboot的自动配置原理、MyBatis的映射机制,以及数据库的设计和优化。同时,通过实际的开发流程,可以学习到如何从需求出发,进行系统分析、设计、编码...
《Spring MVC+MYBatis企业应用实战》是针对已有一定编程框架基础的学习者设计的一份实战教程,旨在深入解析在企业级项目中如何有效结合Spring、Spring MVC和MyBatis这三个核心组件,构建高效、可维护的Web应用程序。...
`mi-clima` 是一个基于Java技术栈的Web应用程序学习实践项目,它结合了MyBatis、Spring、JSF2(JavaServer Faces 2)和Primefaces这四个核心技术,旨在帮助开发者熟悉这些组件的集成与应用。通过分析这个项目,我们...
总的来说,"基于Spring+Spring MVC+Mybatis的图书管理系统源码"是一个典型的Java Web项目,展示了SSM框架在实际开发中的应用,提供了从数据存取、业务处理到用户交互的完整解决方案。通过学习和分析这套源码,开发者...
在本项目中,MyBatis通过Mapper接口与XML配置文件,实现了数据操作的声明式编程,使得数据查询和更新更为直观和可控。 Oracle数据库是关系型数据库管理系统中的佼佼者,以其强大的事务处理能力、高可用性和安全性被...
首先,让我们理解Spring与MyBatis的整合原理。MyBatis-Spring是专门为这两种框架设计的桥梁,它使得MyBatis的SqlSession和Mapper接口可以无缝集成到Spring的管理环境中。通过MyBatis-Spring,我们可以将MyBatis的...
【SpringBoot+Spring+MyBatis-51问-面试用】 1. **SpringBoot** 是什么? SpringBoot 是一款 Java 开发框架,被广泛认为是一个“脚手架”。它的设计目标是简化Spring应用程序的初始设置和开发过程,遵循“约定优于...
6. **项目配置**:分析web.xml、spring配置文件、mybatis配置文件等,理解各个框架之间的集成与配置。 7. **Maven或Gradle构建**:可能涉及到的项目构建工具,用于管理和依赖项的下载。 8. **单元测试与集成测试**:...
在这个"SSM(Spring+springmvc+mybatis)项目实例.zip"压缩包中,包含了一个实际的SSM项目和相关的SQL文件,这将有助于我们深入理解SSM框架的工作原理和应用。 首先,Spring框架是整个SSM中的核心,它负责管理对象...
《基于Servlet+Spring+Mybatis的客户关系管理系统详解》 客户关系管理(CRM)系统是企业信息化建设中的重要组成部分,它帮助企业高效管理客户信息、跟踪销售进度、优化客户服务,从而提高企业的竞争力。本项目采用...