Spring+Mybatis+Mysql整合,尽可能减少xml配置。
清单1 实体类User.java
package com.stone.sm.po;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int id;
private String username;
private String password;
private String gender;
private String email;
private String province;
private String city;
private Date birthday;
public User(){
}
public User(int id, String username, String password, String gender,
String email, String province, String city, Date birthday) {
super();
this.id = id;
this.username = username;
this.password = password;
this.gender = gender;
this.email = email;
this.province = province;
this.city = city;
this.birthday = birthday;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
清单2 Dao层接口
package com.stone.sm.dao;
import com.stone.sm.po.User;
//用户管理的Dao接口
public interface UserDao{
//根据Id查询用户信息
public User findUserById(int id) throws Exception;
}
清单3 Dao层接口实现
package com.stone.sm.dao;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.stone.sm.po.User;
@Repository("userDao")
@Transactional
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao{
@Autowired
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory){
super.setSqlSessionFactory(sqlSessionFactory);
}
public User findUserById(int id) throws Exception {
//继承SqlSessionDaoSupport类,通过this.getSqlSession()得到sqlSession
SqlSession sqlSession = this.getSqlSession();
User user=sqlSession.selectOne("test.findUserById",id);
return user;
}
}
清单4 数据源配置
package com.stone.sm.config;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
public class DataBaseSource {
@Bean(destroyMethod="close")
public DataSource mysqlDataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/mybatis_test?characterEncoding=UTF-8");
ds.setUsername("root");
ds.setPassword("root");
ds.setInitialSize(5);
ds.setMaxActive(10);
return ds;
}
}
清单6 UserMapper.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="test">
<select id="findUserById" parameterType="int" resultType="user">
SELECT * FROM USER WHERE id=#{id}
</select>
</mapper>
注意:这里的输出参数类型的映射为"user",这是因为在后面的代码配置或者xml配置中会设置实体类别名。该文件的路径为:config/sqlmap/UserMapper.xml,其中config是与src同级的Source Folder。
接下来整合Spring+Mybatis。
方式一:配置Mybatis全局文件
清单7 Mybatis全局配置文件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-->
<settings>
<!-- log4j日志输出 -->
<setting name="logImpl" value="LOG4J" />
<!-- 打开延迟加载的开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 将积极加载改为消极加载(及按需加载) -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 打开全局缓存开关(二级缓存)默认值就是true -->
<setting name="cacheEnabled" value="true"/>
</settings>
<!--
别名定义.使用<package>标签,表示扫描该包名下的所有类(除了接口和匿名内部类),如果类名上有注解,则使用注解指定的名称作为别名,
如果没有则使用类名首字母小写作为别名,
如com.stone.webdisk.model.User这个类如果没有设置@Alias注解,则此时会被关联到user这个别名上。
-->
<typeAliases>
<package name="com.stone.sm.po"/>
</typeAliases>
<!-- 加载映射文件 -->
<mappers>
<!-- 通过resource方法一次加载一个映射文件 -->
<mapper resource="sqlmap/UserMapper.xml"/>
<!-- 批量加载mapper
<package name="com.stone.sm.mapper"/>-->
</mappers>
</configuration>
注意:<typeAliases>下的<package>标签,在这里,不再使用<typeAliases>标签下<typeAliase>,而是使用<package>标签,表示扫描该包名下的所有类(除了接口和匿名内部类),如果类名上有注解,则使用注解指定的名称作为别名,如果没有则使用类名首字母小写作为别名,如com.majing.learning.mybatis.entity.User这个类如果没有设置@Alias注解,则此时会被关联到user这个别名上。
清单8 DefaultAppConfig.java
package com.stone.sm.config;
import javax.sql.DataSource;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@Import(DataBaseSource.class)
//开启事务管理,proxyTargetClass= true代表开启类的事务管理
@EnableTransactionManagement(proxyTargetClass = true)
//@PropertySource("classpath:db.properties")
public class DefaultAppConfig {
@Autowired
private DataSource dataSource;
@Bean
public SqlSessionFactoryBean sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
//通过mybatis-config.xml 来设置 typeAliasPackage和mapper
//sqlSessionFactoryBean.setConfigLocation(new ClassPathResource("mybatis/SqlMapConfig.xml"));
return sqlSessionFactoryBean;
}
@Bean
public DataSourceTransactionManager dataSourceTransactionManager() {
return new DataSourceTransactionManager(dataSource);
}
}
方式二:用代码取代Mybatis的全局配置
清单9 DefaultAppConfig.java
package com.stone.sm.config;
import javax.sql.DataSource;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@Import(DataBaseSource.class)
//开启事务管理,proxyTargetClass= true代表开启类的事务管理
@EnableTransactionManagement(proxyTargetClass = true)
//@PropertySource("classpath:db.properties")
public class DefaultAppConfig {
@Autowired
private DataSource dataSource;
@Bean
public SqlSessionFactoryBean sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
//表示扫描该包名下的所有类(除了接口和匿名内部类),如果类名上有注解,则使用注解指定的名称作为别名,如果没有则使用类名首字母小写作为别名,
//如com.stone.webdisk.model.User这个类如果没有设置@Alias注解,则此时会被关联到user这个别名上。
sqlSessionFactoryBean.setTypeAliasesPackage("com.stone.sm.po");
sqlSessionFactoryBean.setConfiguration(sqlMapConfig());
// Resource mapperLocations = new ClassPathResource("sqlmap/UserMapper.xml");
// sqlSessionFactoryBean.setMapperLocations(new Resource[] {mapperLocations});
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:sqlmap/UserMapper.xml"));
return sqlSessionFactoryBean;
}
/**
* 代替sqlMapConfig。xml配置
*/
private org.apache.ibatis.session.Configuration sqlMapConfig() {
org.apache.ibatis.session.Configuration sqlMapConfig = new org.apache.ibatis.session.Configuration();
sqlMapConfig.setLogImpl(Slf4jImpl.class);// logImpl
//打开延迟加载的开关
sqlMapConfig.setLazyLoadingEnabled(true);
//将积极加载改为消极加载(及按需加载)
sqlMapConfig.setAggressiveLazyLoading(false);
//打开全局缓存开关(二级缓存)默认值就是true
sqlMapConfig.setCacheEnabled(true);
return sqlMapConfig;
}
@Bean
public DataSourceTransactionManager dataSourceTransactionManager() {
return new DataSourceTransactionManager(dataSource);
}
}
注意:开启Mybatis的log4j需1包含以下的jar包:
log4j-1.2.17.jar
log4j-api-2.0-rc1.jar
log4j-core-2.0-rc1.jar
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar
清单10 整合
package com.stone.sm.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//@Configuration 注解本质上还是 @Component,因此 <context:component-scan/>
//或者 @ComponentScan 都能处理@Configuration 注解的类
@Configuration
@ComponentScan(basePackages={"com.stone.sm"})
public class SpringConfig {
}
清单11 测试
package com.stone.sm.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.stone.sm.config.SpringConfig;
import com.stone.sm.dao.UserDao;
import com.stone.sm.po.User;
public class UserServiceTest {
private AnnotationConfigApplicationContext applicationContext;
//在执行测试方法之前首先获Spring配置文件对象
//注解Before是在执行本类所有测试方法之前先调用这个方法
@Before
public void setup() throws Exception{
applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
}
@Test
public void testFindUserById() throws Exception{
//通过配置资源对象获取userDao对象
UserDao userDao=(UserDao)applicationContext.getBean("userDao");
//调用UserDao的方法
User user=userDao.findUserById(1);
//输出用户信息
System.out.println(user.getId()+":"+user.getUsername());
}
}
以上是非Mapper代理的查询方法。下面使用Mapper代理来实现上面的查询方法 。
使用Mapper代理,首先得创建一个Mapper代理需要使用的Mapper映射文件。
清单12 UserQueryMapper.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.stone.sm.mapper.UserQueryMapper">
<select id="findUserById" parameterType="int" resultType="user">
SELECT * FROM USER WHERE id=#{id}
</select>
</mapper>
该文件与非代理的Mapper映射文件的区别啊hi:Mapper代理的配置文件的namespace为该Mapper代理接口的路径,由于使用Spring的Mapper扫描类,所以Mapper配置文件必须要跟Mapper代理接口位于同一个包下,且名称一样。
清单13 Mapper代理接口
package com.stone.sm.mapper;
import com.stone.sm.po.User;
public interface UserQueryMapper {
//根据Id查询用户信息
public User findUserById(int id) throws Exception;
}
Mapper代理接口名称与Mapper映射文件相同,方法名与配置文件的id相同,输入输出类型相同
清单14 代理接口的测试
package com.stone.sm.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.stone.sm.config.SpringConfig;
import com.stone.sm.mapper.UserQueryMapper;
import com.stone.sm.po.User;
public class UserMapperTest {
private AnnotationConfigApplicationContext applicationContext;
//在执行测试方法之前首先获Spring配置文件对象
//注解Before是在执行本类所有测试方法之前先调用这个方法
@Before
public void setup() throws Exception{
applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
}
@Test
public void testFindUserById() throws Exception{
//通过配置资源对象获取userDao对象
UserQueryMapper userQueryMapper=(UserQueryMapper)applicationContext.getBean("userQueryMapper");
//调用UserDao的方法
User user=userQueryMapper.findUserById(1);
//输出用户信息
System.out.println(user.getId()+":"+user.getUsername());
}
}
在DefaultAppConfig中添加一行:
@MapperScan(basePackages = { "com.stone.sm.mapper" })
其原理是,在DefaultAppConfig中配置扫描,会从mapper包中扫描出Mapper接口,自动创建代理对象并且在容器中注入。自动扫描出来的Mapper的bean的id为Mapper接口类名(首字母小写),所以这类获取的就是“userQueryMapper”的mapper代理对象。
执行结果:
DEBUG [main] - Returning cached instance of singleton bean 'sqlSessionFactory'
DEBUG [main] - Autowiring by type from bean name 'userQueryMapper' via property 'sqlSessionFactory' to bean named 'sqlSessionFactory'
DEBUG [main] - Invoking afterPropertiesSet() on bean with name 'userQueryMapper'
DEBUG [main] - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
DEBUG [main] - Finished creating instance of bean 'userQueryMapper'
DEBUG [main] - Returning cached instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
DEBUG [main] - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionalEventListenerFactory'
DEBUG [main] - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@bf26484]
DEBUG [main] - Returning cached instance of singleton bean 'lifecycleProcessor'
DEBUG [main] - Returning cached instance of singleton bean 'sqlSessionFactory'
DEBUG [main] - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source
DEBUG [main] - Returning cached instance of singleton bean 'userQueryMapper'
DEBUG [main] - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
DEBUG [main] - Fetching JDBC Connection from DataSource
DEBUG [main] - Returning JDBC Connection to DataSource
1:张三