概述
Spring Boot项目就是尊崇“习惯优于配置“的思想,把过去spring框架项目的各种配置文件都给了默认配置。这个项目出来好几年了,相信大部分团队都用上了。讲真,该项目对于拥抱spring项目大腿的java开发者来说真的是太方便了。
我们在spring boot项目中要使用某个技术,也就是需要和spring整合。所以准确的说这篇文章应该讲Spring中的数据库查询。
查询方式选择
工作这么多年,确实各种奇葩的数据库查询方式都用过,我认为最烂的就是直接在代码中拼接字符串式的SQL语句。其中有一些常用的方式,MyBatis,Spring Jpa,Querydsl。。。
@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.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.2.0version>
dependency>
有注解的方式和mapper.xml的方式,从上面谈到的使用需求来说,在接口上注解一大堆查询字符串(类似spring jpa 的repository上注释@Query),也是很难看的,所以我就不说了。
使用mapper.xml和普通spring项目比,还是简化了很多,因为依赖的类中帮我们做了很多事情。
Resources目录下配置自己的mybatis-config文件
如mybatis-config.xml
<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.querydslgroupId>
<artifactId>querydsl-aptartifactId>
dependency>
<dependency>
<groupId>com.querydslgroupId>
<artifactId>querydsl-jpaartifactId>
dependency>
第二步,Maven加入APT插件
<plugin>
<groupId>com.mysema.mavengroupId>
<artifactId>apt-maven-pluginartifactId>
<version>1.1.3version>
<executions>
<execution>
<goals>
<goal>processgoal>
goals>
<configuration>
<outputDirectory>target/generated-sourcesoutputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessorprocessor>
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 countCitysPiggery(String provinceName,Long dealerId) {
JPAQuery> query = new JPAQuery(entityManager);
QUnitsprofile unitsprofile = QUnitsprofile.unitsprofile;
QCity city = QCity.city;
QProvince province = QProvince.province;
List 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;