Spring全家桶笔记六:数据访问层
Spring数据访问概述
Spring提供了统一的数据访问抽象,简化了JDBC、Hibernate、MyBatis等持久层框架的使用。
JDBC模板
JdbcTemplate基本使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Component public class UserDao { @Autowired private JdbcTemplate jdbcTemplate; public User findById(Long id) { String sql = "SELECT * FROM user WHERE id = ?"; return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), id); } public List<User> findAll() { String sql = "SELECT * FROM user"; return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class)); } public int insert(User user) { String sql = "INSERT INTO user(name, email) VALUES(?, ?)"; return jdbcTemplate.update(sql, user.getName(), user.getEmail()); } }
|
命名参数
1 2 3 4 5 6 7 8
| Map<String, Object> params = new HashMap<>(); params.put("name", "张三"); params.put("email", "zhangsan@example.com"); namedParameterJdbcTemplate.update(sql, params);
namedParameterJdbcTemplate.update(sql, new BeanPropertySqlParameterSource(user));
|
Spring Data JPA
快速开始
1 2 3 4 5 6 7 8 9 10 11 12
| @Entity @Table(name = "t_user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; }
|
1 2 3 4 5 6
| public interface UserRepository extends JpaRepository<User, Long> { User findByName(String name); List<User> findByEmailContaining(String email); }
|
自定义查询
1 2 3 4 5
| @Query("SELECT u FROM User u WHERE u.name = ?1") User findByNameCustom(String name);
@Query(value = "SELECT * FROM user WHERE name = :name", nativeQuery = true) User findByNameNative(@Param("name") String name);
|
复杂查询
1 2 3 4 5 6 7 8 9 10
| public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> { }
Specification<User> spec = (root, query, cb) -> { List<Predicate> predicates = new ArrayList<>(); if (name != null) { predicates.add(cb.like(root.get("name"), "%" + name + "%")); } return cb.and(predicates.toArray(new Predicate[0])); };
|
事务管理
声明式事务
1 2 3 4 5 6 7 8 9 10 11
| @Service public class UserService { @Transactional(isolation = Isolation.READ_COMMITTED, timeout = 30) public void transfer(Long fromId, Long toId, BigDecimal amount) { accountDao.decrease(fromId, amount); accountDao.increase(toId, amount); } }
|
事务传播行为
| 传播行为 |
说明 |
| REQUIRED |
如果有事务则加入,没有则创建 |
| REQUIRES_NEW |
总是创建新事务 |
| SUPPORTS |
有事务则加入,没有则非事务 |
| NOT_SUPPORTED |
非事务执行 |
| MANDATORY |
必须有事务,否则抛异常 |
| NEVER |
必须没有事务,否则抛异常 |
常见问题
1. 懒加载异常
解决方案:开启spring.jpa.open-in-view(但影响性能)或使用EntityGraph
2. N+1问题
解决方案:使用JOIN FETCH或@EntityGraph
3. 乐观锁冲突
使用@Version注解实现乐观锁
总结
Spring数据访问层提供了强大的持久层支持,开发者可以根据项目需求选择合适的持久层方案。Spring Data JPA适合快速开发,JdbcTemplate适合需要精细控制SQL的场景。