七、SpringBoot整合持久化层,配置多数据源(SpringBoot系列)
整合JDBCTemplate
SpringBoot提供了JDBCTemplate,可以直接使用
@Service
public class UserService {
@Autowired
JdbcTemplate jdbcTemplate;
public Integer addUser(User user) {
return jdbcTemplate.update("insert into user (username,address) values (?,?);", user.getUsername(), user.getAddress());
}
public List<User> getAllUsers() {
// 自定义 jdbcType转javaType的转换方式
return jdbcTemplate.query("select * from user", new RowMapper<User>() {
@Override
public User mapRow(ResultSet resultSet, int i) throws SQLException {
User user = new User();
int id = resultSet.getInt("id");
String username = resultSet.getString("username");
String address = resultSet.getString("address");
user.setUsername(username);
user.setId(id);
user.setAddress(address);
return user;
}
});
}
public List<User> getAllUsers2() {
// 转换成指定bean
return jdbcTemplate.query("select * from user", new BeanPropertyRowMapper<>(User.class));
}
}
RowMapper的使用:https://www.jianshu.com/p/be60a81e2fe7
JDBCTemplate 配置多数据源
- 配置
# spring.datasource后跟上自定义name
# 该demo使用的DruidDataSource数据库连接池
spring.datasource.one.url=jdbc:mysql://192.168.66.128:3306/javaboy
spring.datasource.one.username=root
spring.datasource.one.password=123
spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.two.url=jdbc:mysql://192.168.66.128:3306/javaboy2
spring.datasource.two.username=root
spring.datasource.two.password=123
spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
-
配置了多个数据源,需要手动加载
@Configuration public class DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.one") DataSource dsOne() { return DruidDataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.two") DataSource dsTwo() { return DruidDataSourceBuilder.create().build(); } }
-
JdbcTemplate需要手动指定一下加载的数据源,使用@Qualifiler指定要装配的组件的Id
@Configuration public class JdbcTemplateConfig { @Bean JdbcTemplate jdbcTemplateOne(@Qualifier("dsOne") DataSource dsOne) { return new JdbcTemplate(dsOne); } @Bean JdbcTemplate jdbcTemplateTwo(@Qualifier("dsTwo") DataSource dsTwo) { return new JdbcTemplate(dsTwo); } }
@AutoWired是byType的
@Qualifier明确指定使用那个实现类,@Qualifier是byName的。
-
使用JdbcTemplate的时候需要注意注入的是针对哪个数据据源的
@RunWith(SpringRunner.class) @SpringBootTest public class Jdbctemplate2ApplicationTests { // 两种指定注入的方式任选一种 @Autowired @Qualifier("jdbcTemplateOne") JdbcTemplate jdbcTemplateOne; @Resource(name = "jdbcTemplateTwo") JdbcTemplate jdbcTemplateTwo; @Test public void contextLoads() { List<User> list1 = jdbcTemplateOne.query("select * from user", new BeanPropertyRowMapper<>(User.class)); System.out.println(list1); List<User> list2 = jdbcTemplateTwo.query("select * from user", new BeanPropertyRowMapper<>(User.class)); System.out.println(list2); } }
-
整合Mybatis
-
mapper注入 :
-
使用在Mapper上使用
@Mapper
注解 -
或者启动类使用
@MapperScan(basePackage=path)
,整个包扫描
-
-
注意xml文件需要放到resorce才能访问,且和mapper目录一样
- 如果不想用一样的目录,需要在application中配置
mybatis.mapper-locations=classpath:path
,例如:mybatis.mapper-locations=classpath:/mapper/*.xml
- 如果不想放的话,需要在pom文件中配置
<resoure> <!--将src/main/java也设置为静态目录--> <directory>src/main/java</directory> <includes> <!--表示此目录下所有以xml结尾的文件会在package时会当做资源文件打包(放在classpath下),其他文件会被忽略--> <include>**/*.xml</inclued> <filtering>true</filtering> </includes> </resource> <rosource> <directory>src/main/resources</directory> </rosource>
pom中resource的作用:https://blog.csdn.net/qq_44643051/article/details/108194448
- 如果不想用一样的目录,需要在application中配置
-
mybatis日志级别配置
logging.level.org.javaboy.mybatis.mapper=debug
Mybatis配置多数据源
Mybatis多数据源:
- 需要配置多个MybatisConfig:
- 将SqlSessionFactoryBean加载不同的数据源
- 扫描不同的Mpper
-
手动加载DateSource
spring.datasource.one.username=root spring.datasource.one.password=123 spring.datasource.one.url=jdbc:mysql://192.168.66.128:3306/javaboy spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.two.username=root spring.datasource.two.password=123 spring.datasource.two.url=jdbc:mysql://192.168.66.128:3306/javaboy2 spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
@Configuration public class DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.one") DataSource dsOne() { return DruidDataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.two") DataSource dsTwo() { return DruidDataSourceBuilder.create().build(); } }
-
配置MybatisConfig,加载不同的数据源
@Configuration @MapperScan(basePackages = "org.javaboy.mybatis2.mapper1",sqlSessionFactoryRef = "sqlSessionFactory1",sqlSessionTemplateRef = "sqlSessionTemplate1") public class MyBatisConfigOne { @Resource(name = "dsOne") DataSource dsOne; @Bean SqlSessionFactory sqlSessionFactory1() { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); try { bean.setDataSource(dsOne); return bean.getObject(); } catch (Exception e) { e.printStackTrace(); } return null; } @Bean SqlSessionTemplate sqlSessionTemplate1() { return new SqlSessionTemplate(sqlSessionFactory1()); } }
//同上配置一样,只是加载了不同的数据源 @Configuration @MapperScan(basePackages = "org.javaboy.mybatis2.mapper2", sqlSessionFactoryRef = "sqlSessionFactory2", sqlSessionTemplateRef = "sqlSessionTemplate2") public class MyBatisConfigTwo { @Resource(name = "dsTwo") DataSource dsTwo; @Bean SqlSessionFactory sqlSessionFactory2() { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); try { bean.setDataSource(dsTwo); return bean.getObject(); } catch (Exception e) { e.printStackTrace(); } return null; } @Bean SqlSessionTemplate sqlSessionTemplate2() { return new SqlSessionTemplate(sqlSessionFactory2()); } }
-
code双份的mapper
-
使用的时候,调用不同的mapper就可以了
整合Spring Data JPA
- 配置文件
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.username=root
spring.datasource.password=123
spring.datasource.url=jdbc:mysql://192.168.66.128:3306/javaboy?useUnicode=true&characterEncoding=UTF-8
# 启用SQL语句的日志记录
spring.jpa.show-sql=true
spring.jpa.database=mysql
spring.jpa.database-platform=mysql
# 第一次启动根据实体类新建数据库表,之后随实体类变更修改数据库结构
spring.jpa.hibernate.ddl-auto=update
# 指定时mysql5.7的方言,这样新建的表的存储引擎才是innodb,不指定的话就是myisam
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
spring.jpa.hibernate.ddl-auto配置:
- create:每次启动新建表,之前的表和数据被删除
- create-drop:和上面一样,多了一样,在应用关闭的时候,sessionFacorty关闭时,就把表删除
- update: 第一次启动新建表,之后根据实体类变更,修改表结构
- validate:验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值,运行程序会校验实体字段与数据库已有的表的字段类型是否相同,不同会报错
-
新建实体类
// 标识是实体类, name为表名,不填默认为表类同名 @Entity(name = "t_book") public class Book { // jpa的实体类必须有id ,需要用@Id注解 @Id // id生成 @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; // 标识字段名,若类的属性和字段名不相同,可用@Column标识对应关系 @Column(name = "name") private String name; @Column(name = "author") private String author; @Column(name = "create_time") private Instant createTime; }
-
dao层: dao层继承JpaReposityory<实体类、id类型>
public interface BookDao extends JpaRepository<Book, Integer> { // 方法命名规则查询 Book findBookById(Integer id); List<Book> findBookByIdGreaterThan(Integer id); List<Book> findBookByIdLessThanOrNameContaining(Integer id, String name); //jpa的@Query()中默认识别的不是sql,是jpql(面对对象的查询语言),用nativeQuery标识,表示是可以直接执行的sql语言 @Query(value = "select * from t_book where id=(select max(id) from t_book)", nativeQuery = true) Book getMaxIdBook(); // Jpa@Query()修改,参数占位符有两种写法: // 1. ?1 ?2 // 2. 使用@Pararm注解 ,:参数1名称 :参数二名称 //jpa自定义sql修改语句,需要加上`@Modifying`和`@Transcational` // 第一种占位符写法:1. ?1 ?2 @Query(value = "insert into t_book(name,author) values(?1,?2)", nativeQuery = true) @Modifying @Transactional Integer addBook(String name, String author); // 第二种占位符写法:2. 使用@Pararm注解 ,:参数1名称 :参数二名称 @Query(value = "insert into t_book(name,author) values(:name,:author)", nativeQuery = true) @Modifying @Transactional Integer addBook2(@Param("name") String name, @Param("author") String author); }
Spring Data JPA配置多数据源
-
手动加载多数据库源,(和JDBCTemplate和mybatis配置多数据源不同的是,需要添加一个@Primary注解)
@Configuration public class DataSourceConfig { @Bean @Primary // 存在多个实例时,优先使用 @ConfigurationProperties(prefix = "spring.datasource.one") DataSource dsOne() { return DruidDataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.two") DataSource dsTwo() { return DruidDataSourceBuilder.create().build(); } }
-
需要配置多个JpaCondig
- LocalContainerEntityManagerFactoryBean指定不同数据源
- 扫描不同dao包
@Configuration
@EnableJpaRepositories(basePackages = "org.javaboy.jpa2.dao1",entityManagerFactoryRef = "localContainerEntityManagerFactoryBean1",transactionManagerRef = "platformTransactionManager1")
public class JpaConfig1 {
@Autowired
@Qualifier("dsOne")
DataSource dsOne;
@Autowired
JpaProperties jpaProperties;
@Bean
@Primary // 存在多个实例时,优先使用
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean1(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dsOne)
.properties(jpaProperties.getProperties())
// 配置单元(起个名字)
.persistenceUnit("pu1")
// 扫描的实体类包
.packages("org.javaboy.jpa2.bean")
.build();
}
// 事务管理
@Bean
PlatformTransactionManager platformTransactionManager1(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(localContainerEntityManagerFactoryBean1(builder).getObject());
}
}
@Configuration
@EnableJpaRepositories(basePackages = "org.javaboy.jpa2.dao2",entityManagerFactoryRef = "localContainerEntityManagerFactoryBean2",transactionManagerRef = "platformTransactionManager2")
public class JpaConfig2 {
@Autowired
@Qualifier("dsTwo")
DataSource dsTwo;
@Autowired
JpaProperties jpaProperties;
@Bean
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean2(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dsTwo)
.properties(jpaProperties.getProperties())
.persistenceUnit("pu2")
.packages("org.javaboy.jpa2.bean")
.build();
}
@Bean
PlatformTransactionManager platformTransactionManager2(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(localContainerEntityManagerFactoryBean2(builder).getObject());
}
}