SpringBoot项⽬中的数据库查询
1. 概述
Spring Boot项⽬就是尊崇“习惯优于配置“的思想,把过去spring框架项⽬的各种配置⽂件都给了默认配置。这个项⽬出来好⼏年了,相信⼤部分团队都⽤上了。讲真,该项⽬对于拥抱spring项⽬⼤腿的java开发者来说真的是太⽅便了。
我们在spring boot项⽬中要使⽤某个技术,也就是需要和spring整合。所以准确的说这篇⽂章应该讲Spring中的数据库查询。
2. 查询⽅式选择
⼯作这么多年,确实各种奇葩的数据库查询⽅式都⽤过,我认为最烂的就是直接在代码中拼接字符串式的SQL语句。其中有⼀些常⽤的⽅式,MyBatis,Spring Jpa,Querydsl。。。
3. 跨库查询
按理说在同⼀个项⽬跨库查询不应该存在。如果出现了,⼀定是表设计出现问题了。数据库按应⽤分,不同应⽤之间调⽤应该通过RPC。
要实现跨库查询其实就是配置多个数据源
列⼀个配置类UicDatasourceConfig.java,⽐如我这⾥⼜⼀个⽤户中⼼(uic)库:
jpa mybatis@Configuration
@PropertySource("classpath:database.properties")
@EnableJpaRepositories(
basePackages = "pository.uic",
entityManagerFactoryRef = "uicEntityManager",
transactionManagerRef = "uicTransactionManager"
)
public class UicDatasourceConfig {
/**
* @return数据源
*/
@Bean
@Primary
@ConfigurationProperties(prefix = "datasource.uic")
public DataSource uicDataSource(){
ate().build();
}
/**
* @return entityManager
*/
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean uicEntityManager(){
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean uicEntityManager = new LocalContainerEntityManagerFactoryBean();
uicEntityManager.setDataSource(uicDataSource());
uicEntityManager.setPackagesToScan("ity.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包:pository.uic
entity包:ity.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&batis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
有注解的⽅式和l的⽅式,从上⾯谈到的使⽤需求来说,在接⼝上注解⼀⼤堆查询字符串(类似spring jpa 的repository上注释@Query),也是很难看的,所以我就不说了。
使⽤l和普通spring项⽬⽐,还是简化了很多,因为依赖的类中帮我们做了很多事情。
Resources⽬录下配置⾃⼰的mybatis-config⽂件
如l
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-////DTD Config 3.0//EN"
"/dtd/mybatis-3-config.dtd">
<configuration>
<mappers>
<mapper resource="l"/>
</mappers>
</configuration>
系统配置⽂件中配置指定mybatis-config⽂件
dxi.uic.dao=debug #为了打印查询sql
配置却少了很多。
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&sema.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>, QuerydslBinde 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.e q("张三"));
如果⽐较复杂的多表查询就使⽤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(unt(),
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),
In(getConcernUnitIds(dealerId))
).groupBy(unitsprofile.cityId).fetch();
return tupleList.stream().map(FindPiggeryAmountPm::analyticCitysPiggery).List());
}
像SQL⼀样写java代码,看起就舒服多了。
注意:每次查询都应该是独⽴的查询对象JPAQuery,所以不要配置成Spring Bean。
entityManager直接注⼊即可:
@PersistenceContext
private EntityManager entityManager;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论