七、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 配置多数据源

  1. 配置
# 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
  1. 配置了多个数据源,需要手动加载

    @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();
        }
    }
    
    
    1. 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的。

    2. 使用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

  1. mapper注入 :

    1. 使用在Mapper上使用@Mapper注解

    2. 或者启动类使用@MapperScan(basePackage=path),整个包扫描

  2. 注意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

  3. mybatis日志级别配置logging.level.org.javaboy.mybatis.mapper=debug

Mybatis配置多数据源

Mybatis多数据源:

  • 需要配置多个MybatisConfig:
    • 将SqlSessionFactoryBean加载不同的数据源
    • 扫描不同的Mpper
  1. 手动加载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();
        }
    }
    
    
  2. 配置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());
        }
    }
    
  3. code双份的mapper

    七、SpringBoot整合持久化层,配置多数据源(SpringBoot系列)

  4. 使用的时候,调用不同的mapper就可以了

整合Spring Data JPA

  1. 配置文件
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:验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值,运行程序会校验实体字段与数据库已有的表的字段类型是否相同,不同会报错
  1. 新建实体类

    // 标识是实体类, 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;
    }
    
  2. 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配置多数据源

  1. 手动加载多数据库源,(和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();
        }
    }
    
    
  2. 需要配置多个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());
    }
}

上一篇:Spring Boot 2.x基础教程:默认数据源Hikari的配置详解


下一篇:springboot连接数据库时出现Access denied for user ‘用户名‘@‘localhost‘ (using password: NO)