现在springboot的火热程度已经超过了spring了,因为springboot简单快速方便,springboot的初衷就是为了简化spring的配置,是的开发中集成新功能时更快,简化或者减少相关的配置。springboot的基础是“约定大于配置”。整合了所有的框架,可以把springboot当作一个框架集合。
我们来看看spring官网对springboot的特点的描述:
1. 创建独立的Spring应用程序
2.直接嵌入Tomcat、Jetty或Undertow(不需要部署WAR文件)
3.提供自以为是的“starter”依赖项以简化构建配置
4.尽可能自动配置Spring和第三方库
5.提供生产就绪功能,如度量、运行状况检查和外部化配置
6.完全没有代码生成,也不需要XML配置(重点)
今天来介绍下springboot整合mybatis。
一.springboot项目的搭建
1.springboot项目的创建
2.springboot跳转页面,这里跟spring是差不多的。
@RestController
public class HelloController {
@RequestMapping(value = "/hello")
public String hello(){
return "index";
}
} 这里的返回的"index"默认位于resources/static下的。
当springboot启动的时候,我们可以看到这两行:
Tomcat initialized with port(s): 8080 (http) 这一行说明springboot的默认端口为8080。
也可以在application.propertices(application.yml)里面配置:
server:
port:8088
Starting Servlet engine: [Apache Tomcat/9.0.31] 这一行说明springboot内置的tomcat的版本。
这样启动springboot项目后,在浏览器地址栏上输入localhost:8080/hello。就可以打开一个页面。
二.springboot整合mybatis
本文不使用application.properties文件 而使用更加简洁的application.yml文件。将resource文件夹下原有的application.properties文件删除,创建application.yml配置文件(备注:其实SpringBoot底层会把application.yml文件解析为application.properties),
.yml和.properties没什么区别,差异在于yml会有层级的划分,并且注意在冒号:后面要有空格.
在这里是使用的@MapperScan注解来,而不是用的mybatisConfig.xml配置mybatis的。
1.配置数据源,在application.yml的配置文件中。
spring:
datasource:
driver-class-class: com.mysql.jdbc.Driver
## type: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://localhost:3306/zj?serverTimezone=GMT%2B8
username: root
password: root2.配置mybaits的mapper路径
mybatis:
mapper-locations: classpath:mapping/*.xml3.mapper接口
public interface UserMapper {
/***
* 根据主键id查询用户
* @param id
* @return
*/
User selectByPrimaryKey(Integer id);
} 4.user的实体这里就不说了,这个很容易
5.在resources下面创建一个mapping/UserMapper.xml文件,这里的路径是对应上面第二部配置的mybatis的mapper路径的。mapper.xml的namespace就是mapper类的全类名。
<?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.seven.demo.dao.UserMapper">
<resultMap id="baseResultMap" type="cn.seven.demo.entity.User">
<id column="id" jdbcType="INTEGER" property="id"></id>
<result column="realName" jdbcType="VARCHAR" property="realName"></result>
<result column="username" jdbcType="VARCHAR" property="username"></result>
<result column="sex" jdbcType="INTEGER" property="sex"></result>
</resultMap>
<!--根据主键查询值-->
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="baseResultMap">
select * from T_USER where id = #{id}
</select>
</mapper>6.mybatis的测试类
@SpringBootTest(classes = SpringbootdemoApplication.class)
@RunWith(SpringRunner.class)//让测试运行于Spring测试环境
public class MybatisTest {
@Resource
private UserMapper userMapper;
@Test
public void test(){
User user = userMapper.selectByPrimaryKey(1);
System.out.println(user);
}
}到这里springboot整合mybatis就完成了。就是这么简单。
三.配置mybatis多数据源
1. 配置MySQL多数据源
spring:
datasource:
master:
driver-class-class: com.mysql.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://localhost:3306/zj?serverTimezone=GMT%2B8
username: root
password: root
slave:
driver-class-class: com.mysql.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://localhost:3307/zj?serverTimezone=GMT%2B8
username: root
password: root2.由于是多数据源,所以在pringboot都启动类(*Application.java)上需要禁用默认得数据源组件
//禁用默认的数据源组件
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)3.需要自己创建一个动态数据源的组件,这里我创建的是mybatisConfig.java类;
@Configuration
@MapperScan(basePackages = "cn.seven.demo.dao")//扫瞄DAO的包
@Slf4j
public class MybatisConfig {
/**
* 创建主数据源
* @return
*/
@Bean("master")
@Primary //设置优先级
@ConfigurationProperties("spring.datasource.master") //配置属性文件
public DataSource master(){
return DataSourceBuilder.create().build();//builder建造者模式
}
/**
* 创建从数据源
* @return
*/
@Bean("slave")
@Primary
@ConfigurationProperties("spring.datasource.slave")
public DataSource slave(){
return DataSourceBuilder.create().build();
}
/**
* 生成自定义的数据源
* @return
*/
@Bean("dynamicDataSource")
public DataSource dynamicDataSource(){
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object,Object> mapDataSource = new HashMap<Object,Object>(2);
mapDataSource.put("master",master());
mapDataSource.put("slave",slave());
//将master数据源作为指定的数据源
dynamicDataSource.setDefaultDataSource(master());
//将master和slave数据源作为指定的数据源
dynamicDataSource.setDataSource(mapDataSource);
return dynamicDataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
//配置数据源,此处配置为关键配置,如果没有将dynamicDataSource作为数据源则不能实现切换
sessionFactoryBean.setDataSource(dynamicDataSource());
//扫描model-entity的包
sessionFactoryBean.setTypeAliasesPackage("cn.seven.demo.entity");
//扫描映射文件
PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
sessionFactoryBean.setMapperLocations(pathMatchingResourcePatternResolver.getResources("classpath:mapping/*.xml"));
return sessionFactoryBean;
}
/**
* 配置事务管理,使用事务时哎方法头部添加@Transactional注解即可
* @return
*/
@Bean
public PlatformTransactionManager transactionManager(){
return new DataSourceTransactionManager(dynamicDataSource());
}
}4.数据源的注解接口
@Target({ElementType.METHOD,ElementType.TYPE,ElementType.PARAMETER})//设置注解的作用范围
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String value() default "master";
}5.自定义的动态数据源
public class DynamicDataSource extends AbstractRoutingDataSource {
/**
* 如果不希望数据源在启动配置时就加载好,可以定制这个方法,从任何你希望的地方读取并返回数据源,
* 比如从数据库,文件,外部接口等读取数据源信息,并最终返回一个DataSource实现类对象即可
* @return
*/
@Override
protected DataSource determineTargetDataSource() {
return super.determineTargetDataSource();
}
/**
* 如果希望所有的数据源在启动配置时加载好,这里通过设置数据源key值来切换数据源,定制这个方法
* @return
*/
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getDataSourceKey();
}
/**
* 设置默认的数据源
* @param defaultDataSource
*/
public void setDefaultDataSource(Object defaultDataSource){
super.setDefaultTargetDataSource(defaultDataSource);
}
/**
* 社渚数据源
* @param dataSource
*/
public void setDataSource(Map<Object,Object> dataSource){
super.setTargetDataSources(dataSource);
//将数据源的key放到数据源上下文的key集合中,用于切换时判断数据源是否有效
DynamicDataSourceContextHolder.addDataSourceKey(dataSource.keySet());
}
}6.动态数据源上下文
public class DynamicDataSourceContextHolder {
/**
* 用于存放数据源的本地线程
*/
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(){
/**
* 讲master数据源的key作为默认的数据源的key
* @return
*/
@Override
protected String initialValue() {
// return super.initialValue();//
return "master";
}
};
/**数据源的key集合,用于切换时判断数据源是否存在*/
private static List<Object> dataSourceKey = new ArrayList<Object>();
/**
* @return the value of contextHolder
*/
public static ThreadLocal<String> getContextHolder() {
return contextHolder;
}
/**
* @return the value of dataSourceKey
*/
public static List<Object> getDataSourceKey() {
return dataSourceKey;
}
/**
* Sets the dataSourceKey
*
* @param dataSourceKey dataSourceKey
*/
public static void setDataSourceKey(String dataSourceKey) {
contextHolder.set(dataSourceKey);
}
/**
* 重置数据源
*/
public static void cleanDataSource(){
contextHolder.remove();
}
/**
* 判断是否包含数据源
* @param key 数据源的key
* @return yes no
*/
public static boolean containDataSourceKey(String key){
return dataSourceKey.contains(key);
}
/**
* 添加数据源key,支持加多个,所以需要用collection
* @param keys 数据源key
* @return
*/
public static boolean addDataSourceKey(Collection<? extends Object> keys){
return dataSourceKey.add(keys);
}
}7. 动态数据源的切面类
@Aspect
@Order(-1) //优先于事务注解执行
@Component
@Slf4j
public class DynamicDataSourceAspect {
@Before("@annotation(dataSource)")
public void switchDataSource(JoinPoint point,DataSource dataSource){
if(!DynamicDataSourceContextHolder.containDataSourceKey(dataSource.value())){
System.out.println("数据库不匹配 : "+ dataSource.value());
}else{
System.out.println("数据库切换 : "+ dataSource.value());
DynamicDataSourceContextHolder.setDataSourceKey(dataSource.value());
}
}
/**
* 清空数据源
* @param point
* @param dataSource
*/
@After("@annotation(dataSource)")
public void restoreDataSource(JoinPoint point,DataSource dataSource){
DynamicDataSourceContextHolder.cleanDataSource();
System.out.println("数据库连接清空:"+dataSource.value());
}
}
8.注意mapper接口的userMapper的查询方法上设置:@DataSource("slave"),由于我们的默认数据库是master,所以这里需要设置成slave;
/***
* 配置多数据源 注解后面的表示方法
* @param id
* @return
*/
@DataSource("slave")
User selectByPrimaryKey(Integer id);
同时由于在mybaitsConfig里写了扫描映射文件的代码:
//扫描映射文件
PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
sessionFactoryBean.setMapperLocations(pathMatchingResourcePatternResolver.getResources("classpath:mapping/*.xml"));
所以需要将之前在yml文件里设置的读取mapper.xml文件的路径删除。
9.使用上面的测试类测试
到这,springboot整合mybatis并设置多数据源就已经完成了。