在Java互联网编程中,数据大部分存储在数据库和NoSQL工具中;传统的JDBC在执行简单的SQL语句时也需要非常多的代码,包含打开关闭数据库、组装结果等,还有大量的try…catch…finally语句,虽然JDBC的性能是最好的,但代码的可读性和可维护性非常差;
在Spring出现后,Spring提供了JDBC模板模式,就是它自身的JdbcTemplate,可以简化许多代码的编程;但是实际工作中,这个模板也不常用;Spring还提供了支持事务的模板TransactionTemplate,支持Hibernate框架的模板HibernateTemplate,对于MyBatis框架由于版本原因,虽未支持,但MyBatis社区开发了介入Spring的开发包,该包提供了SqlSessionTemplate,且开发者还可以直接使用接口编程;
一、配置数据库资源
配置方式有XML配置或注解,对于项目的公共资源,建议采用XML配置;以XML为例介绍三种配置方式:
(1)使用spring内部提供的类:配置一个最简单的数据源,不支持连接池,一般用于测试;
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root" />
<property name="password" value="123456" />
</bean>
(2)使用第三方数据库连接池
需下载对应的数据库连接池相关包,然后在spring中简单配置,示例为DBCP的数据库连接池:
<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/chapter13"/>
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="maxActive" value="255" /> <!--连接池最大数据库连接数,0表示无限制-->
<!--连接池中最多可空闲maxIdle个连接 ,这里5表示即使没有数据库连接时依然可以保持5个空闲的连接,而不被清除,随时待命,0表示无限制-->
<property name="maxIdle" value="5" />
<property name="maxWait" value="10000" /> <!--最大等待毫秒数,-1表示无限制-->
</bean>
(3)使用JNDI数据库连接池
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/test"/>
</bean>
二、使用JdbcTemplate模板
(1)配置JdbcTemplate:在spring配置文件spring-cfg.xml
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
(2)使用JdbcTemplate操作数据库
主要方法:
-execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句(DDL语句包括: create database,create table,alter table ,drop table,create view,alter view ,drop view 等);
-update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
-query方法及queryForXXX方法:用于执行查询相关语句;
-call方法:用于执行存储过程、函数相关语句;
ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("spring-cfg.xml");
JdbcTemplate jt=ctx.getBean(JdbcTemplate.class);
//JDBC增删查改
//增、删、改:jt.update(...)
//查:jt.query(...)、queryForObject(...)
通过ConnectionCallback和StatementCallback接口可获得JdbcTemplate的Statement回调,使用原生的SQL命令,此时,同样可利用JdbcTemplate提供的系列优点,如一致的异常体系;
(PS:回调:定义一个方法A,使用接口作为A的参数,然后在调用此方法时,必须调用这个接口的实现类,在方法A中调用到实现类定义的同名方法时,就会自动执行实现类中自定义的同名方法)
//使用StatementCallback接口进行回调,这个接口只有一个方法需实现Object doInStatement(Statement stmt),
//在该方法的执行体内,可获得Statement的引用,从而完成数据库的操作
public Role getRoleByStatementCallback(JdbcTemplate jdbcTemplate, String 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.getString("id"));
result.setNote(rs.getString("note"));
result.setName(rs.getString("role_name"));
}
return result;
});
return role;
}
注意,JdbcTemplate不支持事务,如果要支持需要引入对应的事务管理器;在spring中,会在内部判断是否事务交由事务管理器处理,是就从管理器中获取数据库连接,且JdbcTemplate的资源连接的请求关闭也由管理器决定,否数据库资源就有JdbcTemplate自身管理;
三、MyBatis-Spring
MyBatis-Spring项目由MyBatis社区开发,并不是Spring的子框架;
配置MyBatis-Spring项目(mybatis-spring-xxx.jar):
(1)配置数据源,前文已有
(2)配置SqlSessionFactory
MyBatis-Spring项目提供了SqlSessionFactoryBean支持SqlSessionFactory的配置,查看SqlSessionFactoryBean源码可知,其中可以配置几乎所有MyBatis的组件,因此Spring可以通过调用其中的setter方法进行配置;
<!--配置SqlSessionFactoryBean-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--MyBatis配置文件,对于简单配置可以选择通过IoC容器注入-->
<property name="configLocation" value="classpath:sqlMapConfig.xml" />
</bean>
sqlMapConfig.xml:
<?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="cn.infocore.pojo.Role" />
</typeAliases>
<!-- 指定映射器路径 -->
<mappers>
<mapper resource="cn/infocore/mapper/RoleMapper.xml" />
</mappers>
</configuration>
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="cn.infocore.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>
定义命名空间下的接口:
public interface RoleMapper {
public int insertRole(Role role);
public Role getRole(@Param("id") String id);
public int updateRole(Role role);
public int deleteRole(@Param("id") String id);
}
(3)可选配置SqlSessionTemplate,如果SqlSessionFactory和SqlSessionTemplate都配配置,优先选择SqlSessionTemplate;SqlSessionTemplate的优点是线程安全,即确保每个线程使用的SqlSession唯一且不互相冲突,且提供了一系列的增删查改等功能;
配置SqlSessionTemplate:使用构造器创建对象,常用参数有SqlSessionFactory和MyBatis的执行器Executor类型(SIMPLE,REUSE,BATCH);
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory" />
<constructor-arg value="BATCH"/>
</bean>
使用SqlSessionTemplate:运行时,每次使用SqlSessionTemplate都会产生一个新的SqlSession,即线程安全;
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cfg.xml");
SqlSessionTemplate template=ctx.getBean(SqlSessionTemplate.class);
......
template.insert("cn.infocore.mapper.RoleMapper.insertRole", role);
template.selectOne("cn.infocore.mapper.RoleMapper.getRole", id);
template.update("cn.infocore.mapper.RoleMapper.updateRole", role);
template.delete("cn.infocore.mapper.RoleMapper.deleteRole", id);
但由于SqlSessionTemplate需要通过字符串指定调用哪个SQL,不符合面向对象的规范,且IDE并不能检查这个字符串逻辑的正确性,所以,SqlSessionTemplate的运用也不是很多;
(4)配置Mapper:单个配置或者扫描生成Mapper;
MyBatis-Spring提供了一个MapperFactoryBean类作为中介,可以通过配置来实现我们想要的Mapper;使用Mapper接口式编程可以有效地在逻辑代码中擦除SqlSessionTemplate;
配置RoleMapper对象:mapperInterface:映射器的接口
<bean id="roleMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="cn.infocore.mapper.RoleMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" /> <!--失效-->
<property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
</bean>
RoleMapper role=ctx,getBean(RoleMappper.class);
MapperFactoryBean只能配置一个Mapper,如果Mapper很多就会造成配置量很大的问题,因此我们用MapperScannerConfigurer进行配置,用扫描的方式去生成对应的Mapper;
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.infocore.mapper" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<!-- 使用sqlSessionTemplateBeanName将覆盖sqlSessionFactoryBeanName的配置 -->
<!-- <property name="sqlSessionTemplateBeanName" value="sqlSessionFactory"/> -->
<!-- 指定标注才扫描成为Mapper -->
<property name="annotationClass" value="org.springframework.stereotype.Repository" />
</bean>
RoleMapper接口修改:
@Repository
public interface RoleMapper {...}
除了通过basePackage属性扫描Mapper,还可以使用扩展接口名的方式,由于这个需要定义一个接口,且所有Mapper都要扩展它,比较麻烦,因此不是很推荐,就不详述了;
(5)事务管理,这个见深入spring事务管理
综上所述,推荐使用Spring+MyBatis,配置如下:
<?xml version='1.0' encoding='UTF-8' ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!-- 数据库连接池 -->
<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/test" />
<property name="username" value="root" />
<property name="password" value="infocore" />
<!--连接池的最大数据库连接数 -->
<property name="maxActive" value="255" />
<!--最大等待连接中的数量 -->
<property name="maxIdle" value="5" />
<!--最大等待毫秒数 -->
<property name="maxWait" value="10000" />
</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="cn.infocore.mapper" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<property name="annotationClass" value="org.springframework.stereotype.Repository" />
</bean>
</beans>
其他需要的文件:xxxMapper.java接口及对应的xxxMapper.xml、sqlMapConfig.xml;