Spring和数据库编程
Spring最重要的功能就是操作数据。在Java互联网项目中,数据大部分存储在数据库和NoSQL中,数据库的编程时互联网编程的基础,Spring为开发者提供了JDBC的模板模式,那就是JdbcTemplate,它可以简化许多代码的编程,但是在实际中并不常用。
对于持久层,工作中更多的时候用的时Hibernate框架和MyBatis框架,对于Hibernate框架,Spring提供了HibernateTemplate给予支持,它能有效简化对Hibernate的编程。对于MyBatis编程,社区开发了SqlSessionTemplate给开发者使用。
传统的JDBC代码的弊端
示例代码如下:
public Role getRole(Long id) {
Role role = null;
// 声明JDBC变量
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 注册驱动程序
Class.forName("com.mysql.jdbc.Driver");
// 获取连接
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/chapter12", "root", "123456");
// 预编译SQL
ps = con.prepareStatement("select id, role_name, note from t_role where id = ?");
// 设置参数
ps.setLong(1, id);
// 执行SQL
rs = ps.executeQuery();
// 组装结果集返回POJO
while (rs.next()) {
role = new Role();
role.setId(rs.getLong(1));
role.setRoleName(rs.getString(2));
role.setNote(rs.getString(3));
}
} catch (ClassNotFoundException | SQLException e) {
// 异常处理
e.printStackTrace();
} finally {
// 关闭数据库连接资源
try {
if (rs != null && !rs.isClosed()) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (ps != null && !ps.isClosed()) {
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (con != null && !con.isClosed()) {
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return role;
}
使用传统的JDBC执行一条简单的SQL过程如下:首先打开数据库连接执行SQL,然后组装结果,最后关闭数据库资源。但是太多的try…catch…finally…语句,造成了代码的泛滥。
配置数据库资源
在Spring中配置数据库资源很简单,大部分配置成为数据库连接池,既可以使用Spring内部提供的类,也可以使用第三方数据库连接池或者从web服务器中通过JNDI获取数据,由于使用了第三方的类,一般而言在工程中会偏向于采用XML的方式进行配置,当然也可以采用注解的方式进行配置。对于项目的公共资源,建议统一采用XML进行配置。
使用简单数据库配置
它是Spring提供的一个类org.springframework.jdbc.datasource.SimpleDriverSource。它很简单,不支持数据库连接池。可以通过XML的形式配置:
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/chapter12" />
</bean>
这个配置一般用于测试,因为它不是一个数据库连接池,只是一个很简单的数据库连接的应用。
使用第三方数据库连接池
使用DBCP数据库连接池,在Spring中的配置如下:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/chapter12" />
<property name="username" value="root" />
<property name="password" value="123456" />
<!--连接池的最大数据库连接数 -->
<property name="maxActive" value="255" />
<!--最大等待连接中的数量 -->
<property name="maxIdle" value="5" />
<!--最大等待毫秒数 -->
<property name="maxWait" value="10000" />
</bean>
Spring为配置JNDI数据库连接池提供了对应的支持。
使用JNDI数据库连接池
在Tomcat、WebLogic等java EE服务器上配置数据源,这时它存在一个JNDI的名称。也可以通过Spring所提供的JNDI机制获取对应的数据源。
假设在Tomcat上已经配置了jdbc/chapter12的数据源,在项目中获得这个JNDI数据源的代码如下:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/chapter12"/>
</bean>
这样就能够在Spring中定义JNDI数据源了。
JDBC代码失控的解决方案——JdbcTemplate
JdbcTemplate是Spring针对JDBC代码失控提供的解决方案。首先对JdbcTemplate进行配置,代码如下:
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
配置好了dataSource和JdbcTemplate就可以操作JdbcTemplate了,假设Spring配置文件为spring-cfg.xml,则代码如下:
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");
JdbcTemplate jdbcTemplate = ctx.getBean(JdbcTemplate.class);
Long id = 1L;
String sql = "select id, role_name, note from t_role where id = " + id;
Role role = jdbcTemplate.queryForObject(sql, new RowMapper<Role>() {
@Override
public Role mapRow(ResultSet rs, int rownum) throws SQLException {
Role result = new Role();
result.setId(rs.getLong("id"));
result.setRoleName(rs.getString("role_name"));
result.setNote(rs.getString("note"));
return result;
}
});
System.out.println(role.getRoleName());
这是使用了JdbcTemplate的queryForObject方法。它包含两个参数,一个是SQL,另一个是RowMapper接口。而且这里使用了匿名类,所以采用new关键字去创建一个RowMapper接口对象,如果是Java 8,可以采用Lambda表达式的写法,代码如下:
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");
JdbcTemplate jdbcTemplate = ctx.getBean(JdbcTemplate.class);
Long id = 1L;
String sql = "select id, role_name, note from t_role where id = " + id;
Role role = jdbcTemplate.queryForObject(sql, (ResultSet rs, int rownum) -> {
Role result = new Role();
result.setId(rs.getLong("id"));
result.setRoleName(rs.getString("role_name"));
result.setNote(rs.getString("note"));
return result;
});
System.out.println(role.getRoleName());
在mapRow方法中,从ResultSet对象中取出查询得到的数据,组装成一个Role对象,而无须再写任何关闭数据库资源的代码。因为JdbcTemplate内部实现了它们,这便是Spring所提供的模板规则。
JdbcTemplate的增删查改操作
JdbcTemplate的增删查改操作代码如下:
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");
JdbcTemplate jdbcTemplate = ctx.getBean(JdbcTemplate.class);
JdbcTemplateTest test = new JdbcTemplateTest();
test.insertRole(jdbcTemplate);
List roleList = test.findRole(jdbcTemplate, "role");
System.out.println(roleList.size());
Role role = new Role();
role.setId(1L);
role.setRoleName("update_role_name_1");
role.setNote("update_note_1");
test.updateRole(jdbcTemplate, role);
test.deleteRole(jdbcTemplate, 1L);
}
插入角色的代码:
public int insertRole(JdbcTemplate jdbcTemplate) {
String roleName = "role_name_1";
String note = "note_1";
String sql = "insert into t_role(role_name, note) values(?, ?)";
return jdbcTemplate.update(sql, roleName, note);
}
删除角色的代码:
public int deleteRole(JdbcTemplate jdbcTemplate, Long id) {
String sql = "delete from t_role where id=?";
return jdbcTemplate.update(sql, id);
}
更新角色的代码:
public int updateRole(JdbcTemplate jdbcTemplate, Role role) {
String sql = "update t_role set role_name=?, note = ? where id = ?";
return jdbcTemplate.update(sql, role.getRoleName(), role.getNote(), role.getId());
}
查询角色列表的代码:
public List<Role> findRole(JdbcTemplate jdbcTemplate, String roleName) {
String sql = "select id, role_name, note from t_role where role_name like concat('%',?, '%')";
Object[] params = {roleName};//组织参数
//使用RowMapper接口组织返回(使用lambda表达式)
List<Role> list = jdbcTemplate.query(sql, params, (ResultSet rs, int rowNum) -> {
Role result = new Role();
result.setId(rs.getLong("id"));
result.setRoleName(rs.getString("role_name"));
result.setNote(rs.getString("note"));
return result;
});
return list;
}
执行多条SQL
当要多次执行SQL时,可以使用execute方法。它将允许传递ConnectionCallback或者StatementCallback等接口进行回调,从而完成对应的功能。代码如下:
/**
* 使用ConnectionCallback接口进行回调
* @param jdbcTemplate 模板
* @param id 角色编号
* @return 返回角色
*/
public Role getRoleByConnectionCallback(JdbcTemplate jdbcTemplate, Long id) {
Role role = null;
//这里写成Java 8的Lambda表达式,如果你使用低版本的Java,需要使用ConnectionCallback匿名类
role = jdbcTemplate.execute((Connection con) -> {
Role result = null;
String sql = "select id, role_name, note from t_role where id = ?";
PreparedStatement ps = con.prepareStatement(sql);
ps.setLong(1, id);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
result = new Role();
result.setId(rs.getLong("id"));
result.setNote(rs.getString("note"));
result.setRoleName(rs.getString("role_name"));
}
return result;
});
return role;
}
/**
* 使用StatementCallback接口进行回调
* @param jdbcTemplate模板
* @param id角色编号
* @return返回角色
*/
public Role getRoleByStatementCallback(JdbcTemplate jdbcTemplate, Long id) {
Role role = null;
//这里写成Java 8的lambda表达式,如果你使用低版本的Java,需要使用StatementCallback的匿名类
role = jdbcTemplate.execute((Statement stmt) -> {
Role result = null;
String sql = "select id, role_name, note from t_role where id = " + id;
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
result = new Role();
result.setId(rs.getLong("id"));
result.setNote(rs.getString("note"));
result.setRoleName(rs.getString("role_name"));
}
return result;
});
return role;
}
通过实现ConnectionCallback或者StatementCallback接口的方法获取Connection对象或者Statement对象,这样便能够执行多条SQL了。
JdbcTemplate的源码分析
这里查看StatementCallback接口回调的源码:
参考:https://blog.csdn.net/DorMOUSENone/article/details/79046865
@Override
public <T > T execute(StatementCallback < T > action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Connection con = DataSourceUtils.getConnection(getDataSource());
Statement stmt = null;
try {
Connection conToUse = con;
if (this.nativeJdbcExtractor != null && this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}
stmt = conToUse.createStatement(); // 通过连接(Connection)获取一个 Statement
applyStatementSettings(stmt); // 配置 Statement 参数
Statement stmtToUse = stmt;
if (this.nativeJdbcExtractor != null) {
stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
}
// 回调执行 doInXXX() 方法, 并获得 result
T result = action.doInStatement(stmtToUse);
handleWarnings(stmt);
return result;
} catch (SQLException ex) {
//Release Connection early, to avoid potential connection pool deadlock
//in the case when the exception translator hasn't been initialized yet
JdbcUtils.closeStatement(stmt);
stmt = null;
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw getExceptionTranslator().translator("StatementCallback", getSql(action), ex);
} finally {
JdbcUtils.closeStatement(stmt);
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
首先从数据源获取一条连接,然后对接口进行了回调,而在catch语句中会关闭对应的资源。从源码中可以看出,Spring要实现数据库连接资源获取和释放的逻辑,只要完成回调接口的方法逻辑即可,这便是它所提供的模板功能。但是并没有看到任何的事务管理,这是因为JdbcTemplate是不能支持事务的,还需要引入对应的事务管理器才能够支持事务。
只是这里的数据库资源获取和释放的功能还没有那么简单,例如下面的代码:
Connection con = DataSourceUtils.getConnection(getDataSource());
......
DataSourceUtils.releaseConnection(con, getDataSource());
在Spring中,它会在内部再次判断事务是否交由事务管理器处理,如果是,则数据库连接将会从数据库事务管理器中获取,并且JdbcTemplate的资源链接请求的关闭也将由事务管理器决定,而不是由JdbcTemplate自身决定。由于这里只是简单应用,数据库事务并没有交由事务管理器管理,所以数据库资源是由JbdcTemplate自身管理的。
MyBatis-Spring项目
大部分的Java互联网项目,都是用Spring MVC+Spring+MyBatis搭建平台的。使用Spring IoC可以有效管理各类Java资源,达到即插即拔功能;通过AOP框架,数据库事务可以委托给Spring处理,消除很大一部分的事务代码,配合MyBatis的高灵活、可配置、可优化SQL等特性,完全可以构建高性能的大型网站。
配置MyBatis-Spring项目需要以下几步:
- 配置数据源
- 配置SqlSessionFactory
- 可以选择的配置有SqlSessionTemplate,在同时配置SqlSessionTemplate和SqlSessionFactory的情况下,优先采用SqlSessionTemplate。
- 配置Mapper,可以配置单个Mapper,也可以通过扫描的方法生成Mapper,比较灵活。此时Spring IoC会生成对应接口的实例,这样就可以通过注入的方式来获取资源了
- 事务管理
配置SqlSessionFactoryBean
从MyBatis的介绍中,可以知道SqlSessionFactory是产生SqlSession的基础,因此配置SqlSessionFactory十分关键,在MyBatis-Spring项目中提供了SqlSessionFactoryBean去支持SqlSessionFactory的配置,源码如下:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent>{
// 日志
private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class);
// MyBatis配置文件
private Resource configuration;
// Configuration对象
private Configuration configuration;
// Mapper配置路径
private Resource[] mapperLocations;
// 数据库
private DataSource dataSource;
// 事务管理器
private TransactionFactory transactionFactory;
// 配置属性
private Properties configurationProperties;
// SqlSessionFactoryBuilder
private SqlSessionFactoryBuilder SqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// SqlSessionFactory
private SqlSessionFactory SqlSessionFactory;
// environment
// EnvironmentAware requies spring 3.1
private String environment = SqlSessionFactoryBean.class.getSimpleName();
// 当加载后,是否检测所有MyBatis的映射语句加载完全,默认为false
private boolean failFast;
// 插件
private Interceptor[] plugins;
// 类型转换器, typeHandlers
private TypeHandler<?>[] typeHandlers;
// 类型转换器包,用于扫描装载
private String typeHandlersPackage;
// 别名
private Class<?>[] typeAliases;
// 别名包,用于扫描加载
private String typeAliasesPackage;
// 当扩展了上面Class类后,就生成别名,但是如果你没有配置typeAliasesPackage则不会生效
private Class<?>[] typeAliasesSuperType;
// 数据库厂商标识
/ issue #19.No default provider
private DatabaseIdProvider databaseIdProvider;
// unix的文件操作
private Class<? extends VFS> vfs;
// 缓存
private Cache cache;
// ObjectFactory
private ObjectFactory objectFactory;
// 对象包装器
private ObjectWrapperFactory objectWrapperFactory;
/********* setter and getter**********/
}
从源码中可以看出,几乎可以配置所有关于MyBatis的组件,并且它也提供了对应的setter方法让Spring设置它们,所以完全可以通过Spring IoC容器的规则去配置它们。
由于使用了第三方的包,一般而言,更倾向于XML的配置,简单配置如下:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:sqlMapConfig.xml" />
</bean>
这里配置了SqlSessionFactoryBean,但是只是配置了数据源,然后引入了一个MyBatis配置文件,当然如果配置的内容很简单,是可以完全不引入MyBatis配置文件的,只需要通过Spring IoC容器注入即可,但是对于较为复杂的配置,还是建议使用MyBatis的配置文件。配置文件代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 这个配置使全局的映射器启用或禁用缓存 -->
<setting name="cacheEnabled" value="true" />
<!-- 允许 JDBC 支持生成的键。需要适合[修改为:适当]的驱动。如果设置为true,则这个设置强制生成的键被使用,尽管一些驱动拒绝兼容但仍然有效(比如 Derby) -->
<setting name="useGeneratedKeys" value="true" />
<!-- 配置默认的执行器。SIMPLE 执行器没有什么特别之处。REUSE 执行器重用预处理语句。BATCH 执行器重用语句和批量更新 -->
<setting name="defaultExecutorType" value="REUSE" />
<!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 设置超时时间,它决定驱动等待一个数据库响应的时间 -->
<setting name="defaultStatementTimeout" value="25000"/>
</settings>
<!-- 别名配置 -->
<typeAliases>
<typeAlias alias="role" type="com.ssm.chapter12.pojo.Role" />
</typeAliases>
<!-- 指定映射器路径 -->
<mappers>
<mapper resource="com/ssm/chapter12/sql/mapper/RoleMapper.xml" />
</mappers>
</configuration>
这里定义了MyBatis的一些配置项,然后定义了一个角色的别名role,跟着引入了一个映射器RoleMapper.xml,代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ssm.chapter12.mapper.RoleMapper">
<insert id="insertRole" useGeneratedKeys="true" keyProperty="id">
insert into t_role(role_name, note) values (#{roleName}, #{note})
</insert>
<delete id="deleteRole" parameterType="long">
delete from t_role where id=#{id}
</delete>
<select id="getRole" parameterType="long" resultType="role">
select id, role_name as roleName, note from t_role where id = #{id}
</select>
<update id="updateRole" parameterType="role">
update t_role
set role_name = #{roleName},
note = #{roleName}
where id = #{id}
</update>
</mapper>
这里定义了一个命名空间:com.ssm.chapter12.mapper.RoleMapper,并且提供了对角色的增删查改方法。按照MyBatis的规则需要定义一个接口RoleMapper.java,才能够调用它:
import org.apache.ibatis.annotations.Param;
import com.ssm.chapter12.pojo.Role;
public interface RoleMapper {
public int insertRole(Role role);
public Role getRole(@Param("id") Long id);
public int updateRole(Role role);
public int deleteRole(@Param("id") Long id);
}
这里就完成了关于MyBatis框架的主要代码,由于RoleMapper是一个接口,而不是一个类,它没有办法产生实例,那么该如何配置它呢?
SqlSessionTemplate组件
严格地,SqlSessionTemplate并不是一个必须配置的组件,但是它也存在一定的价值。首先,它是线程安全的类,也就是确保每个线程使用的SqlSession唯一且不互相冲突。其次,它提供了一系列的功能,比如增删查改等常用操作。这里首先对其进行配置:
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory" />
<!-- <constructor-arg value="BATCH"/> -->
</bean>
SqlSessionTemplate要通过带有参数的构造方法去创建对象,常用的参数是SqlSessionFactory和MyBatis执行器(Executor)类型,取值范围是SIMPLE、REUSE、BATCH。
篇日志好了SqlSessionTemplate之后,就可以使用它了。增删查改的代码如下:
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");
//ctx为Spring IoC容器
SqlSessionTemplate sqlSessionTemplate = ctx.getBean(SqlSessionTemplate.class);
Role role = new Role();
role.setRoleName("role_name_sqlSessionTemplate");
role.setNote("note_sqlSessionTemplate");
sqlSessionTemplate.insert("com.ssm.chapter12.mapper.RoleMapper.insertRole", role);
Long id = role.getId();
sqlSessionTemplate.selectOne("com.ssm.chapter12.mapper.RoleMapper.getRole", id);
role.setNote("update_sqlSessionTemplate");
sqlSessionTemplate.update("com.ssm.chapter12.mapper.RoleMapper.updateRole", role);
sqlSessionTemplate.delete("com.ssm.chapter12.mapper.RoleMapper.deleteRole", id);
注意:SqlSessionTemplate允许配置执行器的类型,当同时配置SqlSessionFactory和SqlSessionTemplate的时候,SqlSessionTemplate的优先级大于SqlSessionFactory。
配置MapperFactoryBean
MyBatis的运行只需要提供类似于RoleMapper.java接口,而无须提供一个实现类,它是由MyBatis体系创建的动态代理对象运行的,而Spring没有办法为其生成实现类。因此MyBatis-Spring团队提供了一个MapperFactoryBean类作为中介,可以通过配置它来实现我们想要的Mapper。使用了Mapper接口编程方式可以有效地在逻辑代码中擦除SqlSessionTemplate。
配置如下:
<bean id="roleMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!--RoleMapper接口将被扫描为Mapper-->
<property name="mapperInterface" value="com.ssm.chapter12.mapper.RoleMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<!--如果同时注入sqlSessionFactory和sqlSessionTemplate,则只会启用sqlSessionTemplate-->
<property name="sqlSessionTemplate" ref="sqlSessionTemplate]"/>
</bean>
这里的MapperFactoryBean存在3个属性可以配置,分布是mapperInterface、sqlSessionTemplate和SqlSessionFactory,其中:
- mapperInterface是映射器的接口
- 如果同时配置sqlSessionTemplate和SqlSessionFactory,那么它就会启用sqlSessionTemplate。
配置完成这样的一个Bean之后,就可以使用下面代码获取映射器了:
RoleMapper roleMapper = ctx.getBean(RoleMapper.class);
有时候项目会比较大,如果一个个配置Mapper会造成配置量大的问题,MapperScannerConfigurer可以用扫描的形式去生产对应的Mapper。
配置MapperScannerConfigurer
对于MapperScannerConfigurer的主要配置项有:
- basePackages,它指定了让Spring自动扫描什么包,它会逐层深入扫描,如果遇到多个包可以使用半角逗号分隔;
- annotationClass,表示如果类被这个注解标识的时候,才进行扫描。对于开发而言,建议使用这个方式进行注册对应的Mapper。在Spring中往往使用注解@Repository表示数据访问层(DAO)
- SqlSessionFactoryBeanName,指定在Spring中定义SqlSessionFactory的Bean名称。如果sqlSessionTemplateBeanName被定义,那么它将失去作用。
- markerInterface,指定实现了什么接口就认为它是Mapper。需要提供一个公共的接口去标记。
在Spring配置前需要给Mapper一个注解,在Spring中往往使用注解@Repository表示DAO层:
package com.ssm.chapter12.mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import com.ssm.chapter12.pojo.Role;
@Repository
public interface RoleMapper {
public int insertRole(Role role);
public Role getRole(@Param("id") Long id);
public int updateRole(Role role);
public int deleteRole(@Param("id") Long id);
}
然后还要告诉Spring扫描哪个包,这样就可能扫出对应的Mapper到Spring IoC容器中了,代码如下:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.ssm.chapter12.mapper" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<!-- 使用sqlSessionTemplateBeanName将覆盖sqlSessionFactoryBeanName的配置 -->
<!-- <property name="sqlSessionTemplateBeanName" value="sqlSessionFactory"/> -->
<!-- 指定标注才扫描成为Mapper -->
<property name="annotationClass" value="org.springframework.stereotype.Repository" />
</bean>
通过这样的配置Spring IoC容器就知道将包命名为com.ssm.chapter12.mapper,把注解为@Repository的接口扫描为Mapper对象,存放在容器中,对于多个包的扫描可以用半角逗号分隔开。
使用@Repository注解将允许把接口放到各个包当中,然后通过简单的定义类MapperScannerConfigurer的basePackage属性扫描出来,有利于对包的规划。
测试Spring+MyBatis
XML配置文件如下:
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="username" value="root" />
<property name="password" value="123456"/>
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/chapter12" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:sqlMapConfig.xml" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.ssm.chapter12.mapper" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<!-- 使用sqlSessionTemplateBeanName将覆盖sqlSessionFactoryBeanName的配置 -->
<!-- <property name="sqlSessionTemplateBeanName" value="sqlSessionFactory"/> -->
<!-- 指定标注才扫描成为Mapper -->
<property name="annotationClass" value="org.springframework.stereotype.Repository" />
<!-- <property name="markerInterface" value="com.ssm.chapter12.base.BaseMapper"/> -->
</bean>
验证函数如下:
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");
//ctx为Spring IoC容器
RoleMapper roleMapper = ctx.getBean(RoleMapper.class);
Role role = new Role();
role.setRoleName("role_name_mapper");
role.setNote("note_mapper");
roleMapper .insert(role);
Long id = role.getId();
roleMapper.getRole(id);
role.setNote("note_mapper_update");
roleMapper.update(role);
roleMapper.delete(id);