本章是Spring Data系列的第三篇。系列文章,重點不是講解JPA語法,所以跑開了JPA的很多語法等,重點放在環境搭建,通過對比方式,快速體會Spring 對JPA的強大功能。
準備代碼過程中,保持了每個例子的獨立性,和簡單性,準備的源碼包,下載即可使用。如果,對JPA語法想深入研究的話,直接下載在此基礎上進行測試。
前言
Spring Data 系列(一) 入門:簡單介紹了原生態的SQL使用,以及JdbcTemplate的使用,在這裏寫SQL的活還需要自己準備。
Spring Data 系列(二) Spring+JPA入門(集成Hibernate) : 使用JPA API,SQL實現了透明化,可以在不同數據庫之間進行切換,以及JPA解決方案間切換。這時候的業務DAO層,是自定義的方法。
Spring Data 系列(三) Spring+JPA(spring-data-commons): 在Spring Data 系列(二)
的基礎上,業務DAO層,也可以省掉。
1.XML配置實現spring-data-commons集成
環境代碼和項目結構和Spring Data 系列(二) 基本一致
1.1 項目結構
1.2.pom.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
|
< 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.0</ modelVersion > < groupId >com.springframework</ groupId > < artifactId >springJpaExample2</ artifactId > < version >1.0-SNAPSHOT</ version > < packaging >jar</ packaging > < name >springJpaExample2</ name > < url >http://maven.apache.org</ url > < properties > < project.build.sourceEncoding >UTF-8</ project.build.sourceEncoding > </ properties > < dependencies > < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-data-jpa</ artifactId > </ dependency > < dependency > < groupId >mysql</ groupId > < artifactId >mysql-connector-java</ artifactId > </ dependency > < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-test</ artifactId > </ dependency > < dependency > < groupId >junit</ groupId > < artifactId >junit</ artifactId > < version >4.12</ version > </ dependency > </ dependencies > < repositories > < repository > < id >spring-releases</ id > < name >Spring Releases</ name > < url >https://repo.spring.io/libs-release</ url > </ repository > < repository > < id >org.jboss.repository.releases</ id > < name >JBoss Maven Release Repository</ name > < url >https://repository.jboss.org/nexus/content/repositories/releases</ url > </ repository > </ repositories > < pluginRepositories > < pluginRepository > < id >spring-releases</ id > < name >Spring Releases</ name > < url >https://repo.spring.io/libs-release</ url > </ pluginRepository > </ pluginRepositories > < dependencyManagement > < dependencies > < dependency > < groupId >io.spring.platform</ groupId > < artifactId >platform-bom</ artifactId > < version >1.1.2.RELEASE</ version > < type >pom</ type > < scope >import</ scope > </ dependency > </ dependencies > </ dependencyManagement > </ project > |
1.3 persistence.xml
1
2
3
4
5
6
7
|
< persistence version = "2.1" xmlns = "http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" > < persistence-unit name = "JPAExamples" > < provider >org.hibernate.jpa.HibernatePersistenceProvider</ provider > </ persistence-unit > </ persistence > |
1.4 日誌文件(這對研究框架操作過程,是個很好的入口)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<? xml version = "1.0" encoding = "UTF-8" ?> < configuration > < appender name = "STDOUT" class = "ch.qos.logback.core.ConsoleAppender" > < layout class = "ch.qos.logback.classic.PatternLayout" > < Pattern > %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n </ Pattern > </ layout > </ appender > < logger name = "org.hibernate" level = "debug" additivity = "false" > < appender-ref ref = "STDOUT" /> </ logger > < root level = "error" > < appender-ref ref = "STDOUT" /> </ root > </ configuration > |
1.5 核心配置文件spring.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
|
<? 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:p = "http://www.springframework.org/schema/p" xmlns:jpa = "http://www.springframework.org/schema/data/jpa" xmlns:context = "http://www.springframework.org/schema/context" xmlns:aop = "http://www.springframework.org/schema/aop" xmlns:tx = "http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd "> < bean id = "dataSource" class = "org.springframework.jdbc.datasource.DriverManagerDataSource" > < property name = "url" value = "jdbc:mysql://localhost:3306/exampledb" /> < property name = "username" value = "root" /> < property name = "password" value = "root" /> < property name = "driverClassName" value = "com.mysql.jdbc.Driver" /> </ bean > < bean id = "entityManagerFactory" class = "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" > < property name = "dataSource" ref = "dataSource" /> < property name = "persistenceXmlLocation" value = "META-INF/persistence.xml" /> < property name = "persistenceUnitName" value = "JPAExamples" /> < property name = "jpaVendorAdapter" ref = "jpaVendorAdapter" /> < property name = "jpaDialect" ref = "jpaDialect" /> < property name = "jpaProperties" > < props > < prop key = "hibernate.show_sql" >true</ prop > </ props > </ property > </ bean > < bean id = "jpaVendorAdapter" class = "org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" > < property name = "generateDdl" value = "false" /> < property name = "database" value = "MYSQL" /> </ bean > < bean id = "jpaDialect" class = "org.springframework.orm.jpa.vendor.HibernateJpaDialect" /> < bean id = "entityManager" factory-bean = "entityManagerFactory" factory-method = "createEntityManager" ></ bean > <!-- Jpa 事務管理器 --> < bean id = "transactionManager" class = "org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref = "entityManagerFactory" /> <!-- 開啓註解事務 --> < tx:annotation-driven transaction-manager = "transactionManager" proxy-target-class = "true" /> <!-- 啓動對@AspectJ(面向切面)註解的支持 --> < aop:aspectj-autoproxy /> < context:component-scan base-package = "com.journaldev.spring.jpa" ></ context:component-scan > < jpa:repositories base-package = "com.journaldev.spring.jpa" /> </ beans > |
1.6 業務Entity
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
|
package com.journaldev.spring.jpa.model; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.IdClass; @Entity public class Employee { @Id private Integer id; private String name; private String role; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } @Override public String toString() { return "{ID=" + id + ",Name=" + name + ",Role=" + role + "}"; } } |
1.7 DAO
1
2
|
public interface EmployeeDAO extends CrudRepository<Employee,Integer> { } |
DAO接口定義,這兒有幾點2點注意
-
不需要在這兒重複通過@Reposity,@Component等註解聲明Bean,因爲通過<jpa:repositories base-package="com.journaldev.spring.jpa"/>語法已經聲明瞭
-
CrudRepository是泛型,不能省略。
1.8 最後測試
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
|
import com.journaldev.spring.jpa.dao.EmployeeDAO; import com.journaldev.spring.jpa.model.Employee; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; import java.util.Iterator; import java.util.Random; @RunWith (SpringJUnit4ClassRunner. class ) @ContextConfiguration (locations = "classpath:spring.xml" ) public class SpringJPATest /*extends AbstractTransactionalJUnit4SpringContextTests */ { @Autowired private EmployeeDAO employeeDAO; @Test public void testSave(){ Employee emp = new Employee(); int rand = new Random().nextInt( 1000 ); emp.setId(rand); emp.setName( "Pankaj" ); emp.setRole( "Java Developer" ); employeeDAO.save(emp); emp.setName(emp.getName() + "_update" ); employeeDAO.save(emp); Iterable<Employee> employees = employeeDAO.findAll(); Iterator<Employee> iterator = employees.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } } } |
測試代碼,不多測試。還是那句話,該系列文章,重點是演示搭建過程,以及對比方式,理解Spring Data帶來的威力。
最後:
通過對比,相信大家不難發現,本文的DAO層連實現都不需要了,定義一個接口就齊活了,邏輯由Spring自動實時自動生成。最後我要說的時,雖然Spring給我們帶來的便利,但麻煩也隨之而來。把底層實現進行了屏蔽,凡是遇到錯誤,也很難定位問題了,弄清楚Spring的工作機制,這也是我們以後的課題了。
2.Annotation配置實現spring-data-commons集成
和<1.XML配置實現spring-data-commons集成>節基本一樣。
稍微有點差別的是
2.1 spring.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<? 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:p = "http://www.springframework.org/schema/p" xmlns:jpa = "http://www.springframework.org/schema/data/jpa" xmlns:context = "http://www.springframework.org/schema/context" xmlns:aop = "http://www.springframework.org/schema/aop" xmlns:tx = "http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd "> < context:component-scan base-package = "com.journaldev.spring.jpa" ></ context:component-scan > </ beans > |
去除數據庫,事務管理器配置,改用java annotation。相信熟悉spring的同學都知道,他們僅僅是聲明spring bean的方式有點差別,基本本質是一樣,都是註冊BeanDefinition元數據,進而根據元數據構建需要的Bean對象。
2.2 添加配置bean
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
|
package com.journaldev.spring.jpa; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import java.util.Properties; @Configuration @EnableTransactionManagement @EnableJpaRepositories (basePackages = { "com.journaldev.spring.jpa" }) class PersistenceContext { //Configure the required beans here @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setUrl( "jdbc:mysql://localhost:3306/exampledb" ); dataSource.setDriverClassName( "com.mysql.jdbc.Driver" ); dataSource.setUsername( "root" ); dataSource.setPassword( "root" ); return dataSource; } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); entityManagerFactoryBean.setDataSource(dataSource); entityManagerFactoryBean.setJpaVendorAdapter( new HibernateJpaVendorAdapter()); // entityManagerFactoryBean.setPackagesToScan("com.journaldev.spring.jpa"); Properties jpaProperties = new Properties(); //Configures the used database dialect. This allows Hibernate to create SQL //that is optimized for the used database. jpaProperties.put( "hibernate.dialect" , "org.hibernate.dialect.MySQL5Dialect" ); //Specifies the action that is invoked to the database when the Hibernate //SessionFactory is created or closed. jpaProperties.put( "hibernate.hbm2ddl.auto" , true ); //If the value of this property is true, Hibernate writes all SQL //statements to the console. jpaProperties.put( "hibernate.show_sql" , true ); //If the value of this property is true, Hibernate will format the SQL //that is written to the console. jpaProperties.put( "hibernate.format_sql" , true ); entityManagerFactoryBean.setJpaProperties(jpaProperties); return entityManagerFactoryBean; } @Bean public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(entityManagerFactory); return transactionManager; } } |
使用編碼式聲明,我能想到唯一的優點:自動程度高一些,方便動態配置相關信息。
總之,變更了2處地方,其他完全一樣。可以理解爲就是聲明底層支持對象(如數據源,事務管理器)兩個地方發生了變化),看各自愛好,那種方式都可以。我比較傾向於XML聲明方式。
源碼包2個
本文出自 “簡單” 博客,請務必保留此出處http://dba10g.blog.51cto.com/764602/1792855