SpingBoot2.3.1集成Hibernate5之使用配置SessionFactory方式实现兼容BaseDao代码

由于SpringBoot2.3.1默认与Hibernate集成是使用JPA的方式,JPA规范不兼容spring低版本与Hibernate集成实现BaseDao操控数据读取,这里通过手动配置实现兼容。
具体步骤:
1、使用hibernate首先在pom.xml中需要引入一下几个依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

hibernate是使用JPA规范进行开发的,所以spring使用jpa依赖引入hibernate。jdbc的依赖引入不是必须的。
2、启动入口@SpringBootApplication注解中要排除数据源自动配置、JPA自动配置及hibernateJpa自动配置
代码如下:

//启动时将数据源自动配置、JPA自动配置及hibernateJpa自动配置排除掉,如果不排除则将按照springboot的自动设置运行程序,自己写的配置hibernate配置无法生效
@SpringBootApplication(exclude = {
    
    
        DataSourceAutoConfiguration.class,
        JpaRepositoriesAutoConfiguration.class,
        HibernateJpaAutoConfiguration.class })
// 开启事务管理
@EnableTransactionManagement(proxyTargetClass = true)//启用注解事务,即可以使用@Transactional注解来控制事务等同于xml配置方式的 <tx:annotation-driven />
@EnableAspectJAutoProxy//允许AspectJ自动生成代理

public class HibernateproApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(HibernateproApplication.class, args);
    }
}

@EnableTransactionManagement(proxyTargetClass = true)作用是启用注解事务,即可以使用@Transactional注解来控制事务等同于xml配置方式的 <tx:annotation-driven />
@EnableAspectJAutoProxy 作用是允许AspectJ自动生成代理,将@Aspect 注解标注的组件类实现AOP功能。

3、在application.properties配置文件中,进行数据源的配置,下面代码使用了两个数据源进行多数据源的配置

app.datasource.first.driver-class-name=com.mysql.cj.jdbc.Driver
app.datasource.first.jdbc-url=jdbc:mysql://192.168.1.110:3306/lovemall?&serverTimezone=UTC&autoReconnect=true&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
app.datasource.first.username=root
app.datasource.first.password=abc7048461
app.datasource.first.type=com.zaxxer.hikari.HikariDataSource
app.datasource.first.hikari.minimum-idle=5
app.datasource.first.hikari.maximum-pool-size=500
app.datasource.first.hikari.auto-commit=true
app.datasource.first.hikari.idle-timeout=30000
app.datasource.first.hikari.pool-name=DatebookHikariCP1
app.datasource.first.hikari.max-lifetime=1800000
app.datasource.first.hikari.connection-timeout=30000
app.datasource.first.hikari.connection-test-query=SELECT 1

app.datasource.second.driver-class-name=com.mysql.cj.jdbc.Driver
app.datasource.second.jdbc-url=jdbc:mysql://192.168.1.110:3306/lovemall?&serverTimezone=UTC&autoReconnect=true&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true
app.datasource.second.username=root
app.datasource.second.password=abc7048461
app.datasource.second.type=com.zaxxer.hikari.HikariDataSource
app.datasource.second.hikari.minimum-idle=5
app.datasource.second.hikari.maximum-pool-size=500
app.datasource.second.hikari.auto-commit=true
app.datasource.second.hikari.idle-timeout=30000
app.datasource.second.hikari.pool-name=DatebookHikariCP2
app.datasource.second.hikari.max-lifetime=1800000
app.datasource.second.hikari.connection-timeout=30000
app.datasource.second.hikari.connection-test-query=SELECT 1

springboot2.X版本默认使用hikari连接池实现连接数据库,配置文件中针对hikari属性进行配置,需要注意的时高版本的mysql连接器驱动更换成了com.mysql.cj.jdbc.Driver
4、实现数据源的配置,单独声明一个java配置类,配置两个数据源的Bean

@Configuration
public class HibernateDataSourceConfig {
    
    
    //第一个数据源
    @Bean(name = "firstDataSource")
    @ConfigurationProperties(prefix = "app.datasource.first")//application.properties文件中前缀配置引用
    @Primary//多个数据源时首先注入
    public DataSource firstDataSource() {
    
    
        return DataSourceBuilder.create().build();
    }
    //第二个数据源
    @Bean(name="secondDataSource")
    @ConfigurationProperties(prefix="app.datasource.second")//application.properties文件中前缀配置引用
    public DataSource secondDataSource() {
    
    
        return DataSourceBuilder.create().build();
    }
}

通过代码可以看出两个数据源Bean都加入到了spring容器进行管理,第一个数据源为默认数据源名称为firstDataSource,第二个数据源名称为secondDataSource。
5、利用数据源注入配置Hibernate的SessionFactory,代码如下

@Configuration
public class HibernateSessionConfig {
    
    

    //注入第一个数据源,生成sessionFactory
    @Autowired
    @Bean("sessionFactory")
    @Primary
    public LocalSessionFactoryBean getSessionFactory(@Qualifier("firstDataSource")DataSource dataSource) {
    
    
        return buildLocalSessionFactory(dataSource);
    }

    /**
     * 设置Hibernate的配置属性
     * @return
     */
    private Properties getHibernateProperties(){
    
    
        Properties hibernateProperties = new Properties();
        hibernateProperties.put("hibernate.dialect","org.hibernate.dialect.MySQL55Dialect");
        hibernateProperties.put("current_session_context_class", "org.springframework.orm.hibernate5.SpringSessionContext");
        hibernateProperties.put("hibernate.show_sql", "true");
        hibernateProperties.put("hibernate.format_sql", "false");
        hibernateProperties.put("hibernate.hbm2ddl.auto", "update");
        return hibernateProperties;
    }

    /**
     * 构建LocalSessionFactoryBean实例
     * @param dataSource 构建实例所使用的的数据源
     * @return
     */
    private LocalSessionFactoryBean buildLocalSessionFactory(DataSource dataSource){
    
    
        LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
        localSessionFactoryBean.setDataSource(dataSource); // 配置数据源,指定成第一个数据源
        // 如果使用 xml 配置则使用该方法进行包扫描
        //PathMatchingResourcePatternResolver pmprpr = new PathMatchingResourcePatternResolver();
        //Resource[] resource = pmprpr.getResources("classpath*:com/ml/hibernatepro/ml/domain/*.hbm.xml");
        //localSessionFactoryBean.setMappingLocations(resource);

        // 现在配置基本都切换到 java config
        //localSessionFactoryBean.setAnnotatedPackages("classpath*:com/ml/hibernatepro/ml/domain");
        // 添加 Hibernate 配置规则
        localSessionFactoryBean.setHibernateProperties(getHibernateProperties());
        //指定需要扫描的hibernate的Entity实体类包名,可以指定多个包名
        localSessionFactoryBean.setPackagesToScan("com.ml.hibernatepro.ml.domain");
        return localSessionFactoryBean;
    }
    //注入第二个数据源生成secondSessionFactory
    @Autowired
    @Bean("secondSessionFactory")
    public LocalSessionFactoryBean getSecondSessionFactory(@Qualifier("secondDataSource")DataSource dataSource) {
    
    
        return buildLocalSessionFactory(dataSource);
    }
}

通过代码分析可以看出,配置类中使用LocalSessionFactoryBean 生成SessionFactory,具体实现方式与在低版本spring中适应XML配置文件参数配置一致,只是有XML配置换成java配置而已。
代码中使用第一个数据源firstDataSource生成了sessionFactory,使用第二个数据源secondDataSource生成了secondSessionFactory,两个hibernate的会话工厂都加入到spring容器进行管理。
6、使用上步生成的两个会话工厂bean分别配置两个事务管理器,注意事务配置类继承了TransactionManagementConfigurer接口,这个接口的作用是指定一个默认事务管理器,当使用注解@Transactional 没有指定事务管理器名称时,就自动启用默认事务管理器。如果指定名称则按照名称启用指定的事务管理器。

@Configuration
public class TransactionConfig implements TransactionManagementConfigurer {
    
    
    //注入基于第一个数据源生成的会话工厂
    @Autowired
    @Qualifier("sessionFactory")
    private  SessionFactory sessionFactory;

    // 事务管理交给 HibernateTransactionManager
    //基于第一个数据源的事务管理
    @Bean("transactionManager")
    public HibernateTransactionManager getTransactionManager(){
    
    
        HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager();
        hibernateTransactionManager.setSessionFactory(sessionFactory);
        return hibernateTransactionManager;
    }
    //实现接口 TransactionManagementConfigurer 方法,其返回值代表默认使用的事务管理器
    //注意,此处返回的事务管理器就是@Transactional的默认值,如果不返回则需要指明@Transactional使用的事务管理器名称
    //多事务管理器时指明@Transactional(value="transactionManager"),则代表使用的那个事务
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
    
    
        return getTransactionManager();
    }
    //注入基于第二个数据源生成的会话工厂
    @Autowired
    @Qualifier("secondSessionFactory")
    private SessionFactory secondSessionFactory;
    // 事务管理交给 HibernateTransactionManager
    @Bean("queryTransactionManager")
    public HibernateTransactionManager queryTransactionManager(){
    
    
        HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager();
        hibernateTransactionManager.setSessionFactory(secondSessionFactory);
        return hibernateTransactionManager;
    }
    //DAO中使用的组件实例,在service中使用,主从数据库时负责查询
    @Bean(name="queryDaoBulider")
    public QueryDaoBuilder queryDaoBuilder(){
    
    
        QueryDaoBuilder daoBuilder=new QueryDaoBuilder();
        daoBuilder.setSessionFactory(secondSessionFactory);
        return daoBuilder;
    }
    //DAO中使用的组件实例,在service中使用
    @Bean(name="daoBuilder")
    public DaoBuilder daoBuilder(){
    
    
         DaoBuilder daoBuilder=new DaoBuilder();
         daoBuilder.setSessionFactory(sessionFactory);
         return daoBuilder;
     }

}

代码中最后两个Bean,daoBuilder及queryDaoBulider是我的BaseDao接口中要用到的,可以不用参考。到这里就已经完全实现了不使用JPA规范的方式实现与Hibernate进行集成,Hibernate的使用方式与传统BaseDao使用方式一致。
注意:@SpringBootApplication注解类所在的包及子包中,标注@Service、@Component、@Entity等注解的类直接就能扫描并加入spring容器进行管理。如果你所编写的hibernate等java文件不在前面说的位置内,请在启动入口使用@ComponentScan(value = “io.mieux.controller”)注解,可以将多个包扫描加入容器, @ComponentScan 注解相当于之前的 context:component-scan。

猜你喜欢

转载自blog.csdn.net/u011930054/article/details/106856750