现在Spring流行基于Java的配置(JavaConfig),总体来说是充分利用隐式的bean发现机制和自动装配,结合Java显式配置,完成整个项目的配置。《Spring实战(第4版)》第2章和第3章详细介绍了这些技术。
本文根据第11章第11.3节借助Spring Data实现自动化的JPA Repository,整理了一个简单例子,记录下来。
本例子源代码下载地址为:
Spring集成JPA和MyBatis简单例子-20170622
一、用idea创建Maven项目
结构如下图所示
pom.xml配置如下
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.wu.demo.springgroupId>
<artifactId>jpamybatisartifactId>
<version>1.0-SNAPSHOTversion>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<junit.version>4.12junit.version>
<springframework.version>4.3.8.RELEASEspringframework.version>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>1.3.0version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.4.4version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>${springframework.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
<version>${springframework.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>${springframework.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.0.29version>
dependency>
<dependency>
<groupId>org.postgresqlgroupId>
<artifactId>postgresqlartifactId>
<version>42.1.1version>
dependency>
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-jpaartifactId>
<version>1.11.3.RELEASEversion>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-entitymanagerartifactId>
<version>4.3.8.Finalversion>
dependency>
dependencies>
project>
数据源配置文件如下
jdbc.driver = org.postgresql.Driver
db.url = jdbc:postgresql://localhost:5432/test
db.username = postgres
db.password = postgres
initdb.sql不是项目必须的,只是用于建表测试,内容如下:
drop table if exists user_test;
create table user_test (
id varchar(32) primary key,
username varchar(32) not null,
password varchar(32) not null
);
准备工作做完了。
二、创建User类
package com.wu.demo.spring.jpamybatis.bean;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
@Entity
@Table(name="user_test")
public class User {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid")
private String id;
@Column
private String username;
@Column
private String password;
//此处节省篇幅,省略了get/set。
}
三、Dao包中,UserRepository继承JpaRepository。
package com.wu.demo.spring.jpamybatis.dao;
import com.wu.demo.spring.jpamybatis.bean.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository{
}
UserMapper接口如下:
package com.wu.demo.spring.jpamybatis.dao;
import com.wu.demo.spring.jpamybatis.bean.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;
public interface UserMapper {
@Select(value="select * from user_test where username = #{username}")
User getByUsername(@Param("username") String username);
@SelectProvider(type = UserSqlProvider.class, method = "get")
User get(@Param("username") String username, @Param("password") String password);
@UpdateProvider(type = UserSqlProvider.class, method = "update")
void update(User user);
}
UserSqlProvider如下:
package com.wu.demo.spring.jpamybatis.dao;
import com.alibaba.druid.util.StringUtils;
import com.wu.demo.spring.jpamybatis.bean.User;
import org.apache.ibatis.jdbc.SQL;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* MyBatis动态SQL语句构建器,链式SQL构建始于version 3.4.2
*/
@Component
public class UserSqlProvider {
/**
* 根据用户名和密码查询
* @param params
* @return
*/
public String get(Map params){
String username = params.get("username");
String password = params.get("password");
SQL sql = new SQL().SELECT("*").FROM("user_test");
if(!StringUtils.isEmpty(username)){
sql.WHERE("username=#{username}");
}
if(!StringUtils.isEmpty(password)){
sql.WHERE("password=#{password}");
}
return sql.toString();
}
/**
* 修改用户名和密码
* @param user
* @return
*/
public String update(User user){
SQL sql = new SQL().UPDATE("user_test").SET("username = #{username}, password = #{password}")
.WHERE("id=#{id}");
return sql.toString();
}
}
四、Service如下
package com.wu.demo.spring.jpamybatis.service;
import com.wu.demo.spring.jpamybatis.bean.User;
import com.wu.demo.spring.jpamybatis.dao.UserMapper;
import com.wu.demo.spring.jpamybatis.dao.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private UserMapper userMapper;
public void save(User user) {
userRepository.save(user);
}
public User getByUsername(String username){
return userMapper.getByUsername(username);
}
public User get(String username, String password){
return userMapper.get(username, password);
}
public void update(User user){
userMapper.update(user);
}
public void insertAndUpdate(){
User o = new User();
o.setUsername("guest");
o.setPassword("guest123");
save(o);//JPA保存用户
User user = getByUsername("admin");
user.setPassword("admin123456");
update(user);//MyBatis修改用户
// throw new RuntimeException(); //事务测试,抛出异常则全部回滚
}
}
JpaTransactionManager可以同时管理JPA和MyBatis事务。
五、工程主配置文件AppConfig.java如下:
package com.wu.demo.spring.jpamybatis.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
@Configuration
@PropertySource(value={
"classpath:jdbc.properties"})
@ComponentScan(basePackages = {
"com.wu.demo.spring.jpamybatis.service"})
public class AppConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
数据源DataSourceConfig.java配置如下:
package com.wu.demo.spring.jpamybatis.conf;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
@Value("${jdbc.driver}")
private String jdbcDriver;
@Value("${db.url}")
private String dbUrl;
@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
@Bean(destroyMethod = "close")
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(jdbcDriver);
dataSource.setUrl(dbUrl);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
}
JPA和MyBatis配置DaoConfig.java如下:
package com.wu.demo.spring.jpamybatis.conf;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration
@EnableTransactionManagement
@Import({ DataSourceConfig.class })
@EnableJpaRepositories(entityManagerFactoryRef="entityManagerFactory", transactionManagerRef="jpaTransactionManager",
basePackages = "com.wu.demo.spring.jpamybatis.dao")
@MapperScan("com.wu.demo.spring.jpamybatis.dao")//Mapper扫描
public class DaoConfig {
@Bean
public JpaVendorAdapter jpaVendorAdapter(){
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabase(Database.POSTGRESQL);
adapter.setShowSql(true);
adapter.setGenerateDdl(false);
adapter.setDatabasePlatform("org.hibernate.dialect.HSQLDialect");
return adapter;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource){
LocalContainerEntityManagerFactoryBean emfb = new LocalContainerEntityManagerFactoryBean();
emfb.setDataSource(dataSource);
emfb.setJpaVendorAdapter(jpaVendorAdapter());
emfb.setPackagesToScan("com.wu.demo.spring.jpamybatis.bean");
return emfb;
}
@Bean
public JpaTransactionManager jpaTransactionManager(DataSource dataSource) {
JpaTransactionManager jtm = new JpaTransactionManager();
jtm.setEntityManagerFactory(entityManagerFactory(dataSource).getObject());
return jtm;
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
return sessionFactory.getObject();
}
}
六、测试类如下:
package com.wu.demo.spring.jpamybatis.test;
import com.wu.demo.spring.jpamybatis.bean.User;
import com.wu.demo.spring.jpamybatis.conf.AppConfig;
import com.wu.demo.spring.jpamybatis.conf.DataSourceConfig;
import com.wu.demo.spring.jpamybatis.conf.DaoConfig;
import com.wu.demo.spring.jpamybatis.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={AppConfig.class, DataSourceConfig.class, DaoConfig.class})
@Rollback(value = false)//关闭自动事务自动回滚
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void save(){
User o = new User();
o.setUsername("admin");
o.setPassword("admin123");
userService.save(o);
}
@Test
public void getByUsername(){
User o = userService.getByUsername("admin");
System.out.println(o);
}
@Test
public void get(){
User o = userService.get("admin", "admin123");
System.out.println(o);
}
@Test
public void update(){
User o = userService.getByUsername("admin");
o.setUsername("admin2");
o.setPassword("admin222");
userService.update(o);
}
@Test
public void insertAndUpdate(){
userService.insertAndUpdate();
}
}
本例子源代码下载地址为:
Spring集成JPA和MyBatis简单例子-20170622
参考资料如下:
1、Spring4.X + spring MVC + Mybatis3 零配置应用开发框架搭建详解
2、Spring Data JPA @EnableJpaRepositories配置详解
3、Spring事物管理器TransactionManager解析
4、《Spring实战(第4版)》
5、《Spring 3.x企业应用开发实战》