Spring Data JPA

Spring Data JPA —- 使用最简洁的方式实现数据库访问层

配置文件

Maven

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!-- 核心 -->
<!-- spring data jpa 数据库持久层 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${springdatajpa.version}</version>
</dependency>
<!-- 辅助 -->
<!-- hibernate 框架 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>

<!-- 数据库连接池 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>

<!-- 日志框架 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>

<!-- 工具包 -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>

applicationContext-database.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

<!--四大标签扫描位置-->
<context:component-scan base-package="com.yuda"/>

<!--加载配置文件-->
<context:property-placeholder location="classpath*:db.properties"/>
<!--数据库连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>

<!--jpaVendorAdapter(jpa提供商适配器--entityManagerFactory需要的属性)-->
<bean id="adapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true"/>
<property name="database" value="ORACLE"/>
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="showSql" value="true"/>
</bean>
<!--persistenceProvider(持久性提供者--entityManagerFactory需要的属性)-->
<bean id="provider" class="org.hibernate.jpa.HibernatePersistenceProvider"/>

<!--entityManagerFactory-->
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="adapter"/>
<property name="persistenceProvider" ref="provider"/>
<!-- jpa方言 -->
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
<!-- jpa配置 -->
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.query.substitutions" value="true 1, false 0"/>
<entry key="hibernate.default_batch_fetch_size" value="16"/>
<entry key="hibernate.max_fetch_depth" value="2"/>
<entry key="hibernate.generate_statistics" value="true"/>
<entry key="hibernate.bytecode.use_reflection_optimizer"
value="true"/>
<entry key="hibernate.cache.use_second_level_cache" value="false"/>
<entry key="hibernate.cache.use_query_cache" value="false"/>
</map>
</property>
<!-- 扫描有@Entity注解的实体类 -->
<property name="packagesToScan" value="com.yuda.domain"/>
</bean>

<!--JPA事务管理器-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<!--注解事务管理,启用@Transactional注解-->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

<!--扫描spring data jpa的JpaRepository等接口-->
<jpa:repositories base-package="com.yuda.dao"/>
</beans>

dao层

1
2
3
4
5
6
//不用@Repository注解.
//<jpa:repositories base-package="com.yuda.dao"/>会自动扫描接口
//<Area,String>1:表示实体类;2:表示主键;
public interface AreaRepository extends JpaRepository<Area,String>,JpaSpecificationExecutor<Area> {
Area findByProvinceAndCityAndDistrict(String province,String city,String district);
}

service层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//接口
public interface AreaService {
void saveBatch(List<Area> list);
//...等等各种方法
}
//实现类
@Service
@Transactional
public class AreaServiceImpl implements AreaService {
//注入
@Autowired
private AreaRepository areaRepository;

//各种方法的实现...
}

web层(Struts2)

1
2
3
4
5
6
7
8
9
10
@ParentPackage(value = "json-default")
@Namespace("/")
@Controller
@Scope("prototype")//Struts2的Bean创建方式,不能为单例方式
public class AreaAction extends ActionSupport implements ModelDriven<Area> {
//注入Service
@Autowired
private AreaService areaService;
//各种Action...
}

细说DAO层

可以看到DAO层书写的特别简单,那是因为Spring会在底层为应用程序动态的生成实现类,并且实现类默认拥有18个方法,例如findAll,findOne,count等通用的方法,动态的实现类默认是以”接口名+Impl”为类名的,例如AreaRepository的实现类为AreaRepositoryImpl,如果有业务需要手动实现,可以自行编写这个实现类,Spring会自动把两个实现类放到一起.

同时还可以在接口中实现一些查询逻辑,此时接口中的方法名是有意义的,例如上文中的:

1
Area findByProvinceAndCityAndDistrict(String province,String city,String district);

表示查询Area表通过省,市,区作为参数(idea编译工具中可以自动推荐输入,很是方便)

如果通过方法名也无法达到CRUD的需求,还可以通过编写SQL语句来实现(例子中使用了Hibernate,所以可以使用HQL语句来)

例如:

1
2
3
4
5
6
7
8
public interface StandardRepository extends JpaRepository<Standard, Integer> {

List<Standard> findByName(String name);

@Modifying
@Query(value = "update Standard set minLength=?2 where id=?1")
void updateMinLength(Integer id, Integer minLength);
}
  1. ?1表示第一个参数,?2表示第二个参数;
  2. 通过@Query注解其中的value属性可以加入HQL语句;
  3. 如果想使用SQL语句,可以添加nativeQuery = true属性,表示使用原生查询;
  4. 注意: 当执行数据库的增加删除修改操作时(非查询),需要添加@Modifying注解,表示你要对数据库进行改变的操作.

另外一个例子:

1
2
public interface TakeTimeRepository extends JpaRepository<TakeTime,Integer>,JpaSpecificationExecutor<TakeTime> {
}
  1. JpaRepository接口可以自动生成18个方法(包括分页和排序);
  2. JpaSpecificationExecutor接口可以生成用于条件查询的方法,具体方法有:
    1
    2
    3
    4
    5
    T findOne(Specification<T> spec);
    List<T> findAll(Specification<T> spec);
    Page<T> findAll(Specification<T> spec, Pageable pageable);
    List<T> findAll(Specification<T> spec, Sort sort);
    long count(Specification<T> spec);
  3. Specification表示封装的条件,Pageable表示分页查询,Sort表示排序查询.