前言
之前也写过
SpringMVC
+MyBatis
+Spring
的小项目,但是对MyBatis
的了解还是不够深入,配置也只会生搬硬套。刚好求职失败,遂有空,去阅读以下MyBatis-Spring
的官方文档,深入学习一波。
什么是MyBatis-Spring?
MyBatis-Spring
就是帮助你将MyBatis
代码无缝的整合到Spring
中。Spring
将会加载必要的sqlSessionFactory
类和session
类。
配置数据源
classpath:app.properties
配置SqlSessionFactory
我们需要在Spring应用上下文定义一个SqlSessionFactory
和数据源dataSource
。在MyBatis-Spring
中,SqlSessionFacotoryBean
调用其getObject()
方法去创建SqlSessionFactory
实例。创建SqlSessionFactory
实例中用到了享元设计模式,是一个种结构型模式。
- 享元模式(Flyweight Pattern):主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了极少对象数量从而改善应用所需的对象结构的方式。
- 优点:大大减少对象的创建,降低系统的内存,提供效率。
- 缺点: 提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部的状态而改变,否则会造成系统的混乱。
言归正传,首先在这个SqlSessionFactoryBean
类中,调用getObject()
时,会判断sqlSessionFacotory
是否为空,如果不为空直接返回sqlSessionFacotory
。如果为空,则调用afterPropertiesSet()
方法。
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
afterPropertiesSet()
会检查dataSource
和sqlSessionFactoryBuilder
是否为空。接着会调用buildSqlSessionFactory()
方法。
public void afterPropertiesSet() throws Exception {
notNull(dataSource, "Property 'dataSource' is required");
notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
this.sqlSessionFactory = buildSqlSessionFactory();
}
在buildSqlSessionFactory()
方法会读取xml
配置,然后创建sqlSessionFactory
实例。
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
//...省略几百行代码
return this.sqlSessionFactoryBuilder.build(configuration);
}
言归正传,配置如下:
-
mapperLocations
: 我们存放MyBatis
的mapper.xml
文件路径。 -
typeAliasesPackage
:一般对应着我们实体类所在的包。多个package
之间可以用逗号或者分号等来进行分隔。
事务
一个使用MyBatis-Spring
的主要原因是它允许MyBatis
参与到Spring
的事务管理中,而不是给MyBatis
创建一个新的事务管理器。MyBatis-Spring
利用了存在Spring
中的org.springframework.jdbc.datasource.DataSourceTransactionManager
。我们可以通过配置@Transactional
注解面对切面编程。同时我们也可以通常的AOP
来配置Service层的事务。在事务处理期间,一个单独的SqlSession
对象将会被创建和使用,当事务完成时,这个Session
就会以合适的方式进行提交和回滚。具体配置如下:
使用SqlSession
在
MyBatis
中,我们可以使用SqlSessionFactory
来创建SqlSession
。一旦获得了一个session
之后,我们可以使用它来执行映射语句,提交或者回滚。当我们不需要它的时候,我们可以关闭session
。而在
MyBatis-Spring
之后,你不再需要SqlSessionFactory
了,我们的Dao
层可以注入一个线程安全的SqlSession
,然后进行提交或者回滚,最后关闭session
。
SqlSession Template
SqlSession Template
是MyBatis-Spring
的核心,这个类负责MyBatis
的SqlSession
。
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
我们可以知道SqlSessionTemplate
类的构造器第一个参数是SqlSessionFactory
的实例。SqlSessionTemplate
实现了SqlSession
接口。
public class SqlSessionTemplate implements SqlSession {
//...省略n行
}
之前的我是这样配置的:
其实没有必要去Spring.xml
去配置Dao
层,Service
层,Controller
类。可以用注解代替,后面会讲到。对了,SqlSessionTemplate
其实也不需要配,SqlSession
我们可以通过new SqlSessionTemplate()
创建出来。
SqlSessionDaoSupport
SqlSessionDaoSupport
是一个抽象的支持类,为你提供SqlSession
。我们自定义的Dao
层的实现类继承它就行了。调用getSession()
做你想要的。SqlSessionDaoSupport
内部实现:
public abstract class SqlSessionDaoSupport extends DaoSupport {
private SqlSession sqlSession;
private boolean externalSqlSession;
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (!this.externalSqlSession) {
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
}
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSession = sqlSessionTemplate;
this.externalSqlSession = true;
}
/**
* Users should use this method to get a SqlSession to call its statement methods
* This is SqlSession is managed by spring. Users should not commit/rollback/close it
* because it will be automatically done.
*
* @return Spring managed thread safe SqlSession
* 返回线程安全的sqlSession
*/
public SqlSession getSqlSession() {
return this.sqlSession;
}
/**
* {@inheritDoc}
*/
protected void checkDaoConfig() {
notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
}
}
看到getSession()
方法的注释写着,用户不应该去提交,回滚,或者关闭session
的操作,因为session
会自动关闭它。这个方法返回的是一个线程安全的sqlSession
。
使用注解代替XML的配置
如果不使用注解,你的Spring.xml
配置肯定是多的爆炸,比如这样:
如果使用了@Service
,@Component
,@Repository
,@Controller
,@Resource
,@Autowired
这些注解,这些配置统统可以不要。首先要在SpringMVC.xml
配置自动扫描注解的tag
。
-
@Service
用于标注业务Service
层的类上,有value
这个属性。
@Service(value = "adminUserService")
public class AdminUserService implements IAdminUserService {
@Resource(name = "adminUserDao")
private IAdminUserDao adminUserDao;
}
-
@Controller
用于标注控制Controller
层的类上。
@Controller
@RequestMapping("/api/admin")
public class AdminUserController extends BaseController {
@Resource(name = "adminUserService")
private IAdminUserService adminUserService;
}
-
@Repository
用于标注在Dao
层的类上,有value
这个属性。
@Repository(value = "adminUserDao")
public class AdminUserDao extends SqlSessionDaoSupport implements IAdminUserDao {
}
-
@Component
就是把类注册到Spring.xml
文件中。
@Component
public abstract class BaseDao {
protected SqlSession sqlSession;
protected SqlSessionFactory sqlSessionFactory;
@Resource(name = "sqlSessionFactory")
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
public void setSqlSession(SqlSession sqlSession) {
this.sqlSession = sqlSession;
}
public SqlSession getSqlSession() {
return sqlSession;
}
}
Dao
层的类继承它就行了,就可以调用getSqlSession()
进行想要的操作了。
-
@Resource
默认按名称进行装配字段或者setter
方法。名称可以通过name
属性进行指定,如果没有指定name
属性。当注解写在字段上,默认按字段名进行安装名称查找,如果注解写在setter
方法上,默认按属性名进行装配,当找不到与名称相匹配的bean
时候,才会按照类型进行装配。如果name
属性指定了,那么就只能按名称进行装配了。
@Service(value = "adminUserService")
public class AdminUserService implements IAdminUserService {
@Resource(name = "adminUserDao")
private IAdminUserDao adminUserDao;
}
-
@Autowired
:默认按类型装配,默认情况下必须要求依赖对象必须存在,如果要运行null
值,可以设置它的required
属性为false
。如果我们想要使用名称进行装配,可以结合@Qualifier
注解使用。
@Autowired
public void setAdminUserService(IAdminUserService adminUserService) {
this.adminUserService = adminUserService;
}
尾言
明天去看看通用Mapper
和pageHelper
怎么配置。晚安,地球人。