Spring Boot的数据库之旅(二)

配置多数据源

1.什么是数据源?

数据源中存储了所有建立数据库连接的信息,通过提供正确的数据源名称可以找到相应的数据库连接。

2.什么是多数据源?

就是使用多个数据源方法的多个数据库,它们是一一对应的关系。

3.为什么要使用多数据源?

减少单个数据库的压力。

4.开始配置多数据源

4.1 配置test和test2数据源

#与单数据源的区别是多了个数据源的名称
#test数据源
spring.datasource.test.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.test.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
spring.datasource.test.username=root
spring.datasource.test.password=123456abc

#test2数据源
spring.datasource.test2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.test2.url=jdbc:mysql://localhost:3306/test2?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
spring.datasource.test2.username=root
spring.datasource.test2.password=123456abc

#版本在5及以上的要加上MySQL5Dialect而不是MySQLDialect
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
#利用hibernate根据实体类生成数据库表
spring.jpa.properties.hibernate.hbm2ddl.auto=update

4.2 配置好数据源后,新建配置类接收刚刚配置的参数,用@Primary注明主数据源

这里有两种都可以

第一种:

@Configuration
public class DataSourceConfig {
    @Bean(name = "testDataSource")
    @Qualifier("testDataSource")
    @Primary
    @ConfigurationProperties(prefix="spring.datasource.test")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "test2DataSource")
    @Qualifier("test2DataSource")
    @ConfigurationProperties(prefix="spring.datasource.test2")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }
}

第二种:

@Configuration
public class DataSourceConfig{
    //test库
    @Primary
    @Bean(name = "testDataSourceProperties")
    @Qualifier("testDataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.test")
    public DataSourceProperties testDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Primary
    @Bean(name = "testDataSource")
    @Qualifier("testDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.test")
    public DataSource testDataSource(@Qualifier("testDataSourceProperties") DataSourceProperties dataSourceProperties) {
        return dataSourceProperties.initializeDataSourceBuilder().build();
    }

    //test2库
    @Bean(name = "test2DataSourceProperties")
    @Qualifier("test2DataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.test2")
    public DataSourceProperties test2DataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean(name = "test2DataSource")
    @Qualifier("test2DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.test2")
    public DataSource test2DataSource(@Qualifier("test2DataSourceProperties") DataSourceProperties dataSourceProperties) {
        return dataSourceProperties.initializeDataSourceBuilder().build();
    }
}

4.3 对每个数据源进行详细配置

以test数据源为例:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "testEntityManagerFactory",
        transactionManagerRef = "testTransactionManager",
//设置repository类所在包位置
        basePackages = {"com.mrcoder.sbjpamultidb.repository"})

public class testConfig {
    @Autowired
    private HibernateProperties hibernateProperties;
    @Resource
    @Qualifier("testDataSource")
    private DataSource testDataSource;

    @Primary
    @Bean(name = "testEntityManager")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return testEntityManagerFactory(builder).getObject().createEntityManager();
    }

    @Resource
    private JpaProperties jpaProperties;

    /**
     * 设置实体类所在位置
     */
    @Primary
    @Bean(name = "testEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean testEntityManagerFactory(EntityManagerFactoryBuilder builder) {

        Map<String, Object> properties = hibernateProperties.determineHibernateProperties(
                jpaProperties.getProperties(), new HibernateSettings());
        return builder
                .dataSource(testDataSource)
//设置实体类所在包位置
                .packages("com.mrcoder.sbjpamultidb.entity")
                .persistenceUnit("testPersistenceUnit")
                .properties(properties)
                .build();
    }

    @Primary
    @Bean(name = "testTransactionManager")
    public PlatformTransactionManager testTransactionManager(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(testEntityManagerFactory(builder).getObject());
    }
}

以上两个类的位置一定要设计准确,不然会报错,找不到beean。

test2数据源是一样的,只是没有primary,把所有test改成test2就ok。

4.4 基于JPA使用多数据源

新建对应两个数据源的实体类:

@Entity
@Table(name="city")
public class City {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int cityId;
    private String cityName;
    private String cityIntroduce;
//getter setter 构造方法
}

@Entity
@Table(name="house")
public class House {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int houseId;
    private String houseName;
    private String houseIntroduce;
//getter setter 构造方法
}

创建两个实体类对应的数据操作层:

public interface CityRepository extends JpaRepository<City,Integer> {
}

public interface HouseRepository extends JpaRepository<House,Integer> {
}


4.5 创建controller类测试

@RestController
public class TestController {

    @Autowired
    CityRepository cityRepository;

    @Autowired
    HouseRepository houseRepository;

    @GetMapping("/testDataSource")
    public String testDataSource(){
        City city = new City("北京","中国首都");
        cityRepository.save(city);
        House house = new House("豪宅","特别大的豪宅");
        houseRepository.save(house);
        return "success";
    }
}

查询数据库数据已经输入进去。

基于MyBatis使用多数据源

将依赖改为mybatis,配置略有不同。

@Mapper
public interface CityMapper {

    @Select("SELECT * FROM City")
    @Results({
            @Result(property = "cityId",  column = "city_id"),
            @Result(property = "cityName", column = "city_name"),
            @Result(property = "cityIntroduce", column = "city_introduce")
    })
    List<City> getAllCity();
}

@Mapper
public interface HouseMapper {

    @Select("SELECT * FROM House")
    @Results({
            @Result(property = "houseId",  column = "house_id"),
            @Result(property = "houseName", column = "house_name"),
            @Result(property = "houseIntroduce", column = "house_introduce")
    })
    List<House> getAllHouse();
}
@Configuration
@MapperScan(basePackages = "com.springboot.mapper.datasource",
        sqlSessionTemplateRef = "sqlSessionTemplatePrimary")
public class TestDataSourceConfig {
    @Bean(name = "sqlSessionFactoryPrimary")
    @Primary
    public SqlSessionFactory masterSqlSessionFactory(@Qualifier("testDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        //如果使用xml写SQL的话在这里配置
        //bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/datasource/*.xml"));
        return bean.getObject();
    }

    @Bean(name = "transactionManagerPrimary")
    @Primary
    public DataSourceTransactionManager masterDataSourceTransactionManager(@Qualifier("testDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "sqlSessionTemplatePrimary")
    @Primary
    public SqlSessionTemplate masterSqlSessionTemplate(@Qualifier("sqlSessionFactoryPrimary") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

写controller测试

@RestController
public class TestController {

    @Autowired
    HouseMapper houseMapper;

    @Autowired
    CityMapper cityMapper;

    @GetMapping("/testDataSource")
    public Map testDataSource(){
        Map map = new HashMap();
        List<City> cityList=cityMapper.getAllCity();
        List<House> houseList=houseMapper.getAllHouse();
        map.put("cityList",cityList);
        map.put("houseList",houseList);
        return map;
    }
}

在这个过程中也出现很多问题,总结如下:

1.

Description:

Field cityRepository in com.example.demo.controller.TestController required a bean named 'entityManagerFactory' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)

Action:

Consider defining a bean named 'entityManagerFactory' in your configuration.

网上答案都是说删掉hibernate相关包然后update,我试了并没有用。后来发现是配置数据源时://设置repository类所在包位置 basePackages = {"com.mrcoder.sbjpamultidb.repository"}) 这个地方包的位置没配对。

2.

Description:

The bean 'userRepository', defined in null, could not be registered. A bean with that name has already been defined in file [C:\MyWork\workspace_idea\springbootssm\target\classes\com\fantasy\springbootssm\mapper\UserRepository.class] and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

我把所有的实体类和repository放在一起,就报了这个错,直接在默认配置文件设置:spring.main.allow-bean-definition-overriding=true,就可以了,所以说不同种类最好分开放,养成良好习惯。

猜你喜欢

转载自www.cnblogs.com/xc-xinxue/p/12402920.html