引入
SSM即Spring+SpringMVC+MyBatis框架集。
我们知道,SpringMVC框架把众多对象(比如Controlle们)放进了容器中,所以,SpringMVC可以看作是Spring框架的一部分。也可以这么说,Spring与SpringMVC已经完成了整合。
但是,第三方的MyBatis似乎独立于前两者,毕竟MyBatis仅仅是改变了dao(mapper)层的代码编写而已,没有涉及上层以及Spring环境。
让Spring/SpringMVC+MyBatis成为一个整体,就是SSM整合。接下来,我们先学习为什么整合,然后学习如何整合 >_<。
原生MyBatis的弊端分析
在这里,我们不是关注mapper层怎样怎样,而是关注如何调用mapper层,即关注service层的代码编写。
下面是一段关于保存/查询账户信息的经典代码,我们使用原生方式调用mapper层:
@Service("accountService")
public class AccountServiceImpl implements AccountService {
public void save(Account account) throws IOException {
// 1.获取sqlSession对象
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
// 2.通过sqlSession对象获得mapper代理对象
AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);
// 3.使用mapper代理对象调用各种sql逻辑
mapper.save(account);
// 4.提交与关闭sqlSession对象
sqlSession.commit();
sqlSession.close();
}
public List<Account> findAll() throws IOException {
// 1.获取sqlSession对象
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
// 2.通过sqlSession对象获得mapper代理对象
AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);
// 3.使用mapper代理对象调用各种sql逻辑
List<Account> accountList = mapper.findAll();
// 4.提交与关闭sqlSession对象
sqlSession.commit();
sqlSession.close();
return accountList;
}
}
发现了什么问题?先自己思考。
第一个问题及解决思路:
老生常谈,多次加载文件,多次创建对象。
将SqlSessionFactory工厂交给Spring容器管理,并在容器中生成所有的xxxMapper对象;这样,我们直接从容器中拿出xxxMapper使用就行。
第二个问题及解决思路:
手写commit/close事务管理代码,既麻烦,耦合还高。
使用声明式事务控制,经典的AOP思想的体现。
SSM整合代码
① 引入相关坐标
<!-- 就这一个~ -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
② 解决第一个问题——一切对象交由容器
applicationContext.xml(Spring核心配置文件)
-------------------------------------------------------------------------------------------
<!-- 加载外部资源资源文件 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- DataSource数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- sqlSessionFactory工厂对象放入容器(需要配置数据源+MyBatis核心配置文件的位置) -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:sqlMapConfig.xml"/>
</bean>
<!-- 在容器中生成所有的xxxMapper对象(通过一次包的扫描实现) -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.samarua.mapper"/>
</bean>
③ 解决第二个问题——声明式事务控制
applicationContext.xml(Spring核心配置文件)
-------------------------------------------------------------------------------------------
<!-- 提前引入tx命名空间 -->
<!-- 提前配置DataSource数据源 -->
<!-- 1.配置平台事务管理器(第二步要用) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 2.配置增强(即事务管理) -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<!-- 3.配置织入 -->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut-ref="execution(* com.samarua.service.impl.*.*(..))" />
</aop:config>
④ SSM整合后的service层
com.samarua.service.impl.accountServiceImpl实现类
-------------------------------------------------------------------------------------------
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
public void save(Account account) {
accountMapper.save(account);
}
public List<Account> findAll() {
return accountMapper.findAll();
}
}