Spring数据访问:JDBC与事务管理实战指南
Spring数据访问:JDBC、事务管理与ORM集成实战
一、Spring JDBC:简化数据库操作
Spring JDBC模块通过模板模式消除了传统JDBC开发中的样板代码,提供了更简洁的数据访问方式。
1. JdbcTemplate
JdbcTemplate是Spring JDBC的核心类,处理了连接获取、异常转换等底层细节。
@Repository
public class UserRepository {
@Autowired
private JdbcTemplate jdbcTemplate;
public User findById(Long id) {
return jdbcTemplate.queryForObject(
"SELECT * FROM users WHERE id = ?",
(rs, rowNum) -> new User(
rs.getLong("id"),
rs.getString("username"),
rs.getString("email")
),
id
);
}
public int updateEmail(Long id, String newEmail) {
return jdbcTemplate.update(
"UPDATE users SET email = ? WHERE id = ?",
newEmail, id
);
}
}
最佳实践:
- 将JdbcTemplate注入到DAO层类中
- 使用RowMapper或Lambda表达式处理结果集映射
- 对于复杂查询,考虑使用
BeanPropertyRowMapper
2. NamedParameterJdbcTemplate
相比JdbcTemplate的位置参数,NamedParameterJdbcTemplate支持命名参数,提高SQL可读性。
public List<User> findByStatus(String status) {
String sql = "SELECT * FROM users WHERE status = :status";
Map<String, Object> params = new HashMap<>();
params.put("status", status);
return namedParameterJdbcTemplate.query(
sql,
params,
new BeanPropertyRowMapper<>(User.class)
);
}
3. SimpleJdbcInsert
简化INSERT操作,自动处理主键生成等常见需求。
public Long addUser(User user) {
SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate)
.withTableName("users")
.usingGeneratedKeyColumns("id");
Map<String, Object> params = new HashMap<>();
params.put("username", user.getUsername());
params.put("email", user.getEmail());
return insert.executeAndReturnKey(params).longValue();
}
二、Spring事务管理
Spring提供了统一的事务抽象,支持声明式和编程式事务管理。
1. 声明式事务(@Transactional)
@Service
public class OrderService {
@Transactional
public void placeOrder(Order order) {
// 业务逻辑
orderRepository.save(order);
inventoryService.reduceStock(order.getItems());
paymentService.processPayment(order);
}
}
配置要点:
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
2. 编程式事务(TransactionTemplate)
public void batchProcess(List<Data> dataList) {
transactionTemplate.execute(status -> {
try {
dataList.forEach(dataProcessor::process);
return true;
} catch (Exception e) {
status.setRollbackOnly();
throw e;
}
});
}
3. 传播行为与隔离级别
@Transactional(
propagation = Propagation.REQUIRES_NEW,
isolation = Isolation.READ_COMMITTED,
timeout = 30
)
public void criticalOperation() {
// 需要独立事务的关键操作
}
传播行为类型:
- REQUIRED(默认):当前有事务则加入,没有则新建
- REQUIRES_NEW:总是新建事务
- NESTED:嵌套事务
- SUPPORTS/MANDATORY/NOT_SUPPORTED/NEVER
隔离级别:
- DEFAULT:使用数据库默认
- READ_UNCOMMITTED:可能脏读
- READ_COMMITTED:防止脏读
- REPEATABLE_READ:防止不可重复读
- SERIALIZABLE:最高隔离级别
三、ORM集成
1. Hibernate集成
@Configuration
@EnableTransactionManagement
public class HibernateConfig {
@Bean
public LocalSessionFactoryBean sessionFactory(DataSource dataSource) {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setPackagesToScan("com.example.domain");
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
private Properties hibernateProperties() {
Properties props = new Properties();
props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
props.put("hibernate.show_sql", true);
props.put("hibernate.format_sql", true);
return props;
}
@Bean
public HibernateTransactionManager transactionManager(
SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
}
2. JPA集成
@Repository
public class UserRepositoryImpl implements UserRepositoryCustom {
@PersistenceContext
private EntityManager entityManager;
@Override
public List<User> findActiveUsers() {
return entityManager.createQuery(
"SELECT u FROM User u WHERE u.active = true", User.class)
.getResultList();
}
}
3. MyBatis集成
@Mapper
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
User findById(@Param("id") Long id);
@Insert("INSERT INTO users(username, email) VALUES(#{username}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insert(User user);
}
集成配置:
@Configuration
public class MyBatisConfig {
@Bean
public SqlSessionFactory sqlSessionFactory(
DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setTypeAliasesPackage("com.example.domain");
return sessionFactory.getObject();
}
}
四、性能优化建议
JDBC批量操作:
jdbcTemplate.batchUpdate( "INSERT INTO users(username, email) VALUES(?, ?)", users, 100, // 批处理大小 (ps, user) -> { ps.setString(1, user.getUsername()); ps.setString(2, user.getEmail()); } );
连接池配置:
# HikariCP配置示例 spring.datasource.hikari.maximum-pool-size=20 spring.datasource.hikari.connection-timeout=30000 spring.datasource.hikari.idle-timeout=600000
ORM缓存策略:
@Entity @Cacheable @org.hibernate.annotations.Cache( usage = CacheConcurrencyStrategy.READ_WRITE, region = "userCache" ) public class User { // 实体定义 }
五、总结对比
技术 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
JdbcTemplate | 简单CRUD、需要精细控制SQL | 轻量、直接、性能好 | 需要手动处理对象映射 |
Hibernate | 复杂领域模型、快速开发 | 自动化程度高、缓存支持 | 学习曲线陡峭、SQL优化难 |
JPA | 标准规范、需要切换实现 | 标准化、可移植性好 | 功能受限于标准 |
MyBatis | SQL复杂度高、需要精细优化 | SQL控制灵活、学习成本低 | 需要维护XML/注解 |
架构选择建议:
- 简单项目:JdbcTemplate + 事务管理
- 中等复杂度:Spring Data JPA
- 复杂查询需求:MyBatis + JPA混合模式
- 高性能要求:JdbcTemplate + 存储过程
通过合理组合Spring的数据访问技术,可以在开发效率与系统性能之间取得良好平衡。