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);