SpringData JPA基本/高级/多数据源的使用详解
简介
SpringData JPA是Spring框架下的数据访问层框架,它有很多特点:自定义查询方式、事务管理、动态查询语句生成、性能优化等。在本篇文章中,我们将会深入介绍SpringData JPA的基本用法、高级用法以及多数据源的使用详解。
基本用法
1. 实体类定义
在使用SpringData JPA时,需要先定义一个与数据库表进行映射的实体类。例如:
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "name")
private String name;
@Column(name = "sex")
private String sex;
@Column(name = "age")
private Integer age;
// 省略getter和setter方法
}
2. Repository定义
Repository是SpringData JPA中一个重要的接口,它定义了对数据库的一些增删改查操作。例如:
@Repository
public interface UserRepository extends JpaRepository<User,Integer>{
}
3. 测试类定义
@SpringBootTest
class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@Test
void contextLoads() {
}
/**
* 测试新增用户
*/
@Test
public void testAddUser() {
User user = new User();
user.setName("张三");
user.setSex("男");
user.setAge(18);
userRepository.save(user);
}
/**
* 测试删除用户
*/
@Test
public void testDeleteUser() {
userRepository.deleteById(1);
}
/**
* 测试更新用户
*/
@Test
public void testUpdateUser() {
User user = new User();
user.setId(1);
user.setName("李四");
user.setSex("女");
user.setAge(20);
userRepository.save(user);
}
/**
* 测试查询用户
*/
@Test
public void testQueryUser() {
List<User> userList = userRepository.findAll();
System.out.println(userList);
}
}
高级用法
1. 自定义查询方式
在实际开发中,我们可能需要自己写一些查询语句以满足业务需求。SpringData JPA支持自定义查询方式,可以方便地满足我们的需求。例如:
@Repository
public interface UserRepository extends JpaRepository<User,Integer>{
/**
* 根据用户名和性别查询用户信息
*/
@Query("select u from User u where u.name = ?1 and u.sex = ?2")
List<User> findUserByNameAndSex(String name,String sex);
/**
* 根据年龄查询用户信息
*/
List<User> findByAge(Integer age);
}
2. 分页查询
大数据量查询时,一次性查询会影响性能,SpringData JPA提供了分页查询的方式来解决这个问题。例如:
@Repository
public interface UserRepository extends JpaRepository<User,Integer>{
/**
* 根据年龄查询用户信息,分页
*/
Page<User> findByAge(Integer age, Pageable pageable);
}
3. 动态查询语句生成
当我们需要查询时有许多参数是动态的,又不想必要写这么多相似的代码,可以使用动态查询语句生成来解决这个问题。例如:
@Repository
public interface UserRepository extends JpaRepository<User,Integer>,JpaSpecificationExecutor<User>{
}
public class UserSpecification {
public static Specification<User> baseInfo(final Map<String, Object> userMap) {
return new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
List<Predicate> list = new ArrayList<>();
if (userMap.containsKey("name")) {
String name = userMap.get("name").toString();
if (StringUtils.isNotBlank(name)) {
list.add(criteriaBuilder.like(root.get("name").as(String.class), "%" + name + "%"));
}
}
if (userMap.containsKey("sex")) {
String sex = userMap.get("sex").toString();
if (StringUtils.isNotBlank(sex)) {
list.add(criteriaBuilder.equal(root.get("sex").as(String.class), sex));
}
}
if (userMap.containsKey("age")) {
String age = userMap.get("age").toString();
if (StringUtils.isNotBlank(age)) {
list.add(criteriaBuilder.equal(root.get("age").as(String.class), age));
}
}
Predicate[] p = new Predicate[list.size()];
return criteriaBuilder.and(list.toArray(p));
}
};
}
}
@Repository
public interface UserRepository extends JpaRepository<User,Integer>,JpaSpecificationExecutor<User>{
/**
* 动态查询用户
*/
Page<User> findAll(Specification<User> specification, Pageable pageable);
}
多数据源的使用详解
在SpringData JPA中使用多数据源,需要在SpringBoot的启动类中定义多个数据源。例如:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
@Primary
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public JdbcTemplate primaryJdbcTemplate(DataSource primaryDataSource) {
return new JdbcTemplate(primaryDataSource);
}
@Bean
public JdbcTemplate secondaryJdbcTemplate(DataSource secondaryDataSource) {
return new JdbcTemplate(secondaryDataSource);
}
}
其中primaryDataSource
和secondaryDataSource
是两个数据源,primaryJdbcTemplate
和secondaryJdbcTemplate
是对应数据源的JdbcTemplate。
在实现时,需要将对应的Repository的entityManagerFactory属性指向特定的数据源,如下例所示:
@Repository
public interface UserRepository extends JpaRepository<User,Integer>,JpaSpecificationExecutor<User>{
@PersistenceContext(unitName = "primaryEntityManagerFactory")
EntityManager primaryEntityManager;
@PersistenceContext(unitName = "secondaryEntityManagerFactory")
EntityManager secondaryEntityManager;
}
示例说明
示例一
现在,我们有一个场景:在用户注册之前需要先查询数据库中是否已经存在该用户,如果已经存在则不能注册。我们可以使用SpringData JPA的自定义查询方式来实现。例如:
public interface UserRepository extends JpaRepository<User,Long>,JpaSpecificationExecutor<User>{
/**
* 根据用户名和性别查询用户信息
*/
@Query("select u from User u where u.name = ?1 and u.sex = ?2")
List<User> findUserByNameAndSex(String name,String sex);
}
在用户注册时,首先调用findUserByNameAndSex方法查询数据库中是否存在该用户。例如:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
/**
* 用户注册
*/
public void register(User user) {
List<User> userList = userRepository.findUserByNameAndSex(user.getName(), user.getSex());
if (!userList.isEmpty()) {
throw new RuntimeException("该用户已存在");
}
userRepository.save(user);
}
}
示例二
现在,我们需要查询具有相同年龄的用户列表,并进行分页。我们可以使用SpringData JPA的分页查询来实现。例如:
public interface UserRepository extends JpaRepository<User,Long>,JpaSpecificationExecutor<User> {
/**
* 根据年龄查询用户信息,分页
*/
Page<User> findByAge(Integer age, Pageable pageable);
}
在查询时,我们给出年龄和页数以及每页显示的数量,例如:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
private static final int PAGE_SIZE = 10;
/**
* 查询用户列表(分页)
*/
public Page<User> getUsersByAge(Integer age, Integer pageNum) {
return userRepository.findByAge(age, PageRequest.of(pageNum - 1, PAGE_SIZE));
}
}
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringData JPA基本/高级/多数据源的使用详解 - Python技术站