背景考慮到公司應用中數據庫訪問的多樣性和復雜性,目前正在開發UDSL(統一數據訪問層),開發到一半的時候,偶遇
SpringData工程。發現兩者的思路驚人的一致。
于是就花了點時間了解SpringData,可能UDSL II期會基于SpringData做擴展
SpringData相關資料介紹:針對關系型數據庫,KV數據庫,Document數據庫,Graph數據庫,Map-Reduce等一些主流數據庫,采用統一技術進行訪問,并且盡可能簡化訪問手段。
目前已支持的數據庫有(主要):
MongoDB,Neo4j,Redis,Hadoop,JPA等
SpringData官方資料(強烈推薦,文檔非常詳細)
SpringData主頁:
http://www.springsource.org/spring-dataSpringDataJPA 指南文檔:
http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html/ (非常詳細)
SpringDataJPA Examples: https://github.com/SpringSource/spring-data-jpa-examples (非常詳細的例子)
Spring-Data-Jpa簡介Spring Data Jpa 極大簡化了數據庫訪問層代碼,只要3步,就能搞定一切
1. 編寫Entity類,依照JPA規范,定義實體
2. 編寫Repository接口,依靠SpringData規范,定義數據訪問接口(注意,只要接口,不需要任何實現)
3. 寫一小陀配置文件 (Spring Scheme配置方式極大地簡化了配置方式)
下面,我依賴Example中的例子,簡單地介紹下以上幾個步驟
User.java

User.java
1 /**
2 * User Entity Sample
3 *
4 * @author <a href="mailto:li.jinl@alibaba-inc.com">Stone.J</a> Aug 25, 2011
5 */
6 @Entity
7 public class User extends AbstractPersistable<Long> {
8
9 private static final long serialVersionUID = -2952735933715107252L;
10
11 @Column(unique = true)
12 private String username;
13 private String firstname;
14 private String lastname;
15
16 public String getUsername() {
17 return username;
18 }
19
20 public void setUsername(String username) {
21 this.username = username;
22 }
23
24 public String getFirstname() {
25 return firstname;
26 }
27
28 public void setFirstname(String firstname) {
29 this.firstname = firstname;
30 }
31
32 public String getLastname() {
33 return lastname;
34 }
35
36 public void setLastname(String lastname) {
37 this.lastname = lastname;
38 }
39 沒什么技術,JPA規范要求怎么寫,它就怎么寫
Repository.java

SimpleUserRepository.java
1 /**
2 * User Repository Interface.
3 *
4 * @author <a href="mailto:li.jinl@alibaba-inc.com">Stone.J</a> Aug 25, 2011
5 */
6 public interface SimpleUserRepository extends CrudRepository<User, Long>, JpaSpecificationExecutor<User> {
7
8 public User findByTheUsersName(String username);
9
10 public List<User> findByLastname(String lastname);
11
12 @Query("select u from User u where u.firstname = ?")
13 public List<User> findByFirstname(String firstname);
14
15 @Query("select u from User u where u.firstname = :name or u.lastname = :name")
16 public List<User> findByFirstnameOrLastname(@Param("name") String name);
17
18 需要關注它繼承的接口,我簡單介紹幾個核心接口
Repository: 僅僅是一個標識,表明任何繼承它的均為倉庫接口類,方便Spring自動掃描識別
CrudRepository: 繼承Repository,實現了一組CRUD相關的方法
PagingAndSortingRepository: 繼承CrudRepository,實現了一組分頁排序相關的方法
JpaRepository: 繼承PagingAndSortingRepository,實現一組JPA規范相關的方法
JpaSpecificationExecutor: 比較特殊,不屬于Repository體系,實現一組JPA Criteria查詢相關的方法
不需要寫任何實現類,Spring Data Jpa框架幫你搞定這一切。
Spring Configuration

Configuration.xml
1 <beans>
2 <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
3 <property name="dataSource" ref="dataSource" />
4 <property name="jpaVendorAdapter">
5 <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
6 <property name="generateDdl" value="true" />
7 <property name="database" value="HSQL" />
8 </bean>
9 </property>
10 <property name="persistenceUnitName" value="jpa.sample" />
11 </bean>
12
13 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
14 <property name="entityManagerFactory" ref="entityManagerFactory" />
15 </bean>
16
17 <jdbc:embedded-database id="dataSource" type="HSQL" />
18
19
20 <jpa:repositories base-package="org.springframework.data.jpa.example.repository.simple" />
21 </beans>核心代碼只要配置一行:<jpa:repositories base-package="org.springframework.data.jpa.example.repository.simple" />即可。上面的僅僅是數據源,事務的配置而已。
至此,大功告成,即可運行

Sample.java
1 /**
2 * Intergration test showing the basic usage of {@link SimpleUserRepository}.
3 *
4 * @author <a href="mailto:li.jinl@alibaba-inc.com">Stone.J</a> Aug 25, 2011
5 */
6 @RunWith(SpringJUnit4ClassRunner.class)
7 @ContextConfiguration(locations = "classpath:simple-repository-context.xml")
8 @Transactional
9 public class SimpleUserRepositorySample {
10
11 @Autowired
12 SimpleUserRepository repository;
13 User user;
14
15 @Before
16 public void setUp() {
17 user = new User();
18 user.setUsername("foobar");
19 user.setFirstname("firstname");
20 user.setLastname("lastname");
21 }
22
23 // crud方法測試
24 @Test
25 public void testCrud() {
26 user = repository.save(user);
27 assertEquals(user, repository.findOne(user.getId()));
28 }
29
30 // method query測試
31 @Test
32 public void testMethodQuery() throws Exception {
33 user = repository.save(user);
34 List<User> users = repository.findByLastname("lastname");
35 assertNotNull(users);
36 assertTrue(users.contains(user));
37 }
38
39 // named query測試
40 @Test
41 public void testNamedQuery() throws Exception {
42 user = repository.save(user);
43 List<User> users = repository.findByFirstnameOrLastname("lastname");
44 assertTrue(users.contains(user));
45 }
46
47 // criteria query測試
48 @Test
49 public void testCriteriaQuery() throws Exception {
50 user = repository.save(user);
51 List<User> users = repository.findAll(new Specification<User>() {
52
53 @Override
54 public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
55 return cb.equal(root.get("lastname"), "lastname");
56 }
57 });
58 assertTrue(users.contains(user));
59 }
60 其中,寫操作相對比較簡單,我不做詳細介紹,針對讀操作,我稍微描述下:
Method Query: 方法級別的查詢,針對
findBy
, find
, readBy
, read
, getBy等前綴的方法,解析方法字符串,生成查詢語句,其中支持的關鍵詞有:

Named Query: 針對一些復雜的SQL,支持原生SQL方式,進行查詢,保證性能
Criteria Query: 支持JPA標準中的Criteria Query
備注:
本文只是簡單介紹SpringDataJpa功能,要深入了解的同學,建議直接傳送到
官方網站