Spring Boot项目中的数据库查询

  1. 概述
    Spring Boot项目就是尊崇“习惯优于配置“的思想,把过去spring框架项目的各种配置文件都给了默认配置。这个项目出来好几年了,相信大部分团队都用上了。讲真,该项目对于拥抱spring项目大腿的java开发者来说真的是太方便了。
    我们在spring boot项目中要使用某个技术,也就是需要和spring整合。所以准确的说这篇文章应该讲Spring中的数据库查询。

  2. 查询方式选择
    工作这么多年,确实各种奇葩的数据库查询方式都用过,我认为最烂的就是直接在代码中拼接字符串式的SQL语句。其中有一些常用的方式,MyBatis,Spring Jpa,Querydsl。。。

  3. 跨库查询
    按理说在同一个项目跨库查询不应该存在。如果出现了,一定是表设计出现问题了。数据库按应用分,不同应用之间调用应该通过RPC。
    要实现跨库查询其实就是配置多个数据源
    列一个配置类UicDatasourceConfig.java,比如我这里又一个用户中心(uic)库:
@Configuration
@PropertySource("classpath:database.properties")
@EnableJpaRepositories(
        basePackages = "com.medxi.uic.repository.uic",
        entityManagerFactoryRef = "uicEntityManager",
        transactionManagerRef = "uicTransactionManager"
)
public class UicDatasourceConfig {

    /**
     * @return 数据源
     */
    @Bean
    @Primary
    @ConfigurationProperties(prefix = "datasource.uic")
    public DataSource uicDataSource(){
        return DataSourceBuilder.create().build();
    }

    /**
     * @return entityManager
     */
    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean uicEntityManager(){
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);
        LocalContainerEntityManagerFactoryBean uicEntityManager = new LocalContainerEntityManagerFactoryBean();
        uicEntityManager.setDataSource(uicDataSource());
        uicEntityManager.setPackagesToScan("com.medxi.uic.entity.uic");
        uicEntityManager.setJpaVendorAdapter(vendorAdapter);
        return uicEntityManager;
    }

    /**
     * @return TransactionManager
     */
    @Bean
    @Primary
    public PlatformTransactionManager uicTransactionManager(){
        return new JpaTransactionManager(uicEntityManager().getObject());
    }
   /**
   * @return uicEntityManager
   */
    @Bean
    public EntityManager uicEntityManager(){
         return uicEntityManagerFactory().getObject().createEntityManager();
    }

}

对应该数据库源的实体类和repository(dao)层都应该独立的pakage,在配置的时候要指定。如这里的:
repository包:com.medxi.uic.repository.uic
entity包:com.medxi.uic.entity.uic
类似配置另一个数据源,注意由于两个数据源相关bean都是同类型,所以一个需要注释@Primary。
不同库的数据库信息配置都可以配置在Resources目录下的资源文件database.properties中,根据自己具体配置,选择前缀。
如我这里uic:

datasource.uic.url=jdbc:mysql://127.0.0.1/um_uic
datasource.uic.username=medxi
.
.
.

由于自己配制了数据源,就可以不用spring自动配置了,需要在启动类中排除掉

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

注意使用数据源注入的时候需要指定,如

@Autowired() @Qualifier("uicEntityManager")  
或者
@Resource(name="uicEntityManager")  

接下来就可以按照自己需要使用了
4. Spring jpa
这个spring自己家的,使用最方便,基本不需要配置,用spring boot项目的同学应该都了解了。
无非就是定义一个基础BaseRepository,如:

@NoRepositoryBean
public interface BaseRepository<T> extends JpaRepository<T, String>,JpaSpecificationExecutor<T> {

}

继承的东西可以跟需要进行调整
5. MyBatis
自己写一堆sql在代码中确实很讨厌,但是遇到需要跨库(同数据源),或者大半页面都是一个查询的时候咋办?所以MyBatis还是很需要的,这里介绍一下使用MyBatis的配置
首先当然是引入依赖:

   <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.2.0</version>
        </dependency>

有注解的方式和mapper.xml的方式,从上面谈到的使用需求来说,在接口上注解一大堆查询字符串(类似spring jpa 的repository上注释@Query),也是很难看的,所以我就不说了。
使用mapper.xml和普通spring项目比,还是简化了很多,因为依赖的类中帮我们做了很多事情。
Resources目录下配置自己的mybatis-config文件
如mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <mappers>
        <mapper resource="mapper/IUICQueryMapper.xml"/>
    </mappers>
</configuration>

系统配置文件中配置指定mybatis-config文件

mybatis.config-location=classpath:mybatis-config.xml
logging.level.com.medxi.uic.dao=debug #为了打印查询sql

IUICQueryMapper.xml这个文件就不多说了,和在spring中使用一样
com.medxi.uic.dao包下创建IUICQueryMapper.java,类注释@Mapper,剩下的就和以前使用一样了
配置却少了很多。
6. Querydsl
Querydsl的使用,spring boot的官方指南中就提到了。之前看了觉得spring jpa就做了查询,没考虑这个。最近遇到大量复杂查询的时候,又想通过java代码优雅体现的时候,终于发现她的好了。
第一步,添加依赖,spring boot已经对其依赖版本做了管理,所以不需要列版本

<dependency>
     <groupId>com.querydsl</groupId>
     <artifactId>querydsl-apt</artifactId>
 </dependency>
 <dependency>
     <groupId>com.querydsl</groupId>
     <artifactId>querydsl-jpa</artifactId>
 </dependency>

第二步,Maven加入APT插件

 <plugin>
                <groupId>com.mysema.maven</groupId>
                <artifactId>apt-maven-plugin</artifactId>
                <version>1.1.3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>process</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>target/generated-sources</outputDirectory>
                            <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

注意每次新增或者修改entity都需要执行maven的编译,它才会在对象的实体类目录下创建查询对象,名字就是实体类名前多个“Q”。这样才能使用。
第三步,我们创建一个BaseQuerydslRepository.java供其他单个实体查询时使用

@NoRepositoryBean
public interface BaseQuerydslRepository<T, Q extends EntityPath<?>> extends CrudRepository<T, String>, QueryDslPredicateExecutor<T>, QuerydslBinderCustomizer<Q> {
    default void customize(QuerydslBindings bindings, Q root) {
        bindings.bind(String.class).first(StringExpression::containsIgnoreCase);
    }
}

这样简单查询就可以调用方法:

Iterable<T> findAll(Predicate var1);

Predicate由实体类对应的查询对象生成。
比如现在可以用一个UserRepository去继承,根据用户名查询:

QUser user = QUser.user;
userRepository.findAll(user.userName.eq("张三"));

如果比较复杂的多表查询就使用JPAQuery对象
来个实际例子:

public List<FindPiggeryAmountPm> countCitysPiggery(String provinceName,Long dealerId) {
        JPAQuery<?> query = new JPAQuery<Void>(entityManager);
        QUnitsprofile unitsprofile = QUnitsprofile.unitsprofile;
        QCity city = QCity.city;
        QProvince province = QProvince.province;
        List<Tuple> tupleList = query.from(unitsprofile)
                .select(unitsprofile.cityId.count(),
                        city.cityName,
                        unitsprofile.latitude,
                        unitsprofile.longitude)
                .leftJoin(unitsprofile.stateId,province)
                .leftJoin(unitsprofile.cityId,city)
                .where(unitsprofile.unitType.id.eq(Constant.UNIT_TYPE_PIGGERY),
                        province.provinceName.eq(provinceName),
                        unitsprofile.id.notIn(getConcernUnitIds(dealerId))
                ).groupBy(unitsprofile.cityId).fetch();
       return tupleList.stream().map(FindPiggeryAmountPm::analyticCitysPiggery).collect(Collectors.toList());
    }

像SQL一样写java代码,看起就舒服多了。
注意:每次查询都应该是独立的查询对象JPAQuery,所以不要配置成Spring Bean。
entityManager直接注入即可:

@PersistenceContext
private EntityManager entityManager;
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值