Skip to content

Commit 442e3ff

Browse files
committed
add README_zh.md
1 parent 8253c82 commit 442e3ff

1 file changed

Lines changed: 388 additions & 0 deletions

File tree

README_zh.md

Lines changed: 388 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,388 @@
1+
# spring-data-ebean-spring-boot
2+
> Spring data ebean integration with Spring Boot
3+
4+
[![Build Status](https://travis-ci.org/hexagonframework/spring-data-ebean-spring-boot.svg?branch=master)](https://travis-ci.org/hexagonframework/spring-data-ebean-spring-boot)
5+
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.hexagonframework.boot/spring-data-ebean-spring-boot/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.github.hexagonframework.boot/spring-data-ebean-spring-boot)
6+
7+
[QQ群: 635113788]
8+
9+
[Spring Data](http://projects.spring.io/spring-data/)项目的主要目标是使构建使用DDD仓储接口与实现的Spring应用程序变得更加容易。此模块是基于[Ebean ORM](https://ebean-orm.github.io)(轻量级JPA)的仓储层实现。
10+
通过使用此模块,你可以在基于Ebean ORM下使用Spring Data模式带来的便利性。
11+
如果你还没有接触过[Spring Data](http://projects.spring.io/spring-data/)[Ebean ORM](https://ebean-orm.github.io),建议先了解下该项目。
12+
13+
## 支持的一些特性 ##
14+
15+
* 对标准Entity支持完整CRUD操作,包括常用的查询操作
16+
* 支持通过接口中的注解生成对应的查询(orm查询、sql查询、命名orm查询、命名sql查询)
17+
* 支持通过接口中的方法名生成对应的查询
18+
* 支持QueryChannel服务
19+
* 提供基础属性的实体基类
20+
* 原生支持使用注解实现审计(如创建人、创建时间、修改人、最后修改时间)
21+
* 支持自定义编写基于Ebean的查询,方便而不失灵活性
22+
* 方便的与Spring集成
23+
* 支持MySQL、Oracle、SQL Server、H2、PostgreSQL等数据库
24+
25+
#### 实现的场景 ####
26+
1. Fetch single entity based on primary key
27+
2. Fetch list of entities based on condition
28+
3. Save new single entity and return primary key
29+
4. Batch insert multiple entities of the same type and return generated keys
30+
5. Update single existing entity - update all fields of entity at once
31+
6. Fetch many-to-one relation (Company for Department)
32+
7. Fetch one-to-many relation (Departments for Company)
33+
8. Update entities one-to-many relation (Departments in Company) - add two items, update two items and delete one item - all at once
34+
9. Complex select - construct select where conditions based on some boolean conditions + throw in some JOINs
35+
10. Execute query using JDBC simple Statement (not PreparedStatement)
36+
11. Remove single entity based on primary key
37+
38+
## 为什么选择[Ebean ORM](https://ebean-orm.github.io)
39+
40+
基于JPA注解的轻量级ORM实现,支持Mybatis不支持的实体关联,但相比Hibernate/JPA具有Mybatis的查询灵活性,支持查询[partial objects](https://ebean-orm.github.io/docs/query/partialobjects)
41+
对于实现领域模型仓储接口的聚合根实体保存(保存聚合根实体同时保存聚合根上的关联实体、值对象)和partial objects等技术要求,Ebean都非常适用。
42+
43+
我选择关系型数据持久化框架的基本原则:
44+
1. 拥抱SQL而非隐藏
45+
2. 可以实现面向领域编程
46+
3. 可以利用JPA注解,但不能是JPA的完整实现(这点我偏向于Ebean)
47+
4. 足够成熟以应对企业级应用(Ebean和Hibernate同时期作品,资格老,而且持续更新以满足更高需求)
48+
49+
#### 框架优缺点比较
50+
**Hibernate/JPA**
51+
* [Compare to JPA](http://ebean-orm.github.io/architecture/compare-jpa)
52+
* 反正比Hibernate/JPA好
53+
54+
**MyBatis**
55+
* 优点
56+
* 在XML映射文件里写SQL语句很爽
57+
* 缺点
58+
* 实现一个DAO、仓储要写很多文件,方法多了比较繁琐
59+
* 无法在一个方法里做批处理,无法级联加载
60+
* 无法面向对象,无法实现DDD
61+
62+
**EBean**
63+
* 优点
64+
* 所有场景都实现非常完美,代码可读性高
65+
* 实现批处理超级简单
66+
* ORM查询、sql查询、DTO查询都非常简单
67+
* 缺点
68+
* 还没发现
69+
70+
## 快速开始 ##
71+
72+
建立maven项目,建立spring-boot项目,映入依赖
73+
```
74+
<dependency>
75+
<groupId>io.github.hexagonframework.boot</groupId>
76+
<artifactId>spring-boot-starter-data-ebean</artifactId>
77+
<version>1.2.0.RELEASE</version>
78+
</dependency>
79+
```
80+
81+
参看实例:[spring-boot-data-ebean-samples](https://github.com/hexagonframework/spring-boot-data-ebean-samples)
82+
83+
84+
1、创建一个表格实体类或SQL实体类或DTO类:
85+
86+
表格实体:
87+
```java
88+
@Entity
89+
public class User {
90+
91+
@Id
92+
@GeneratedValue
93+
private Integer id;
94+
private String firstname;
95+
private String lastname;
96+
@Column(nullable = false, unique = true) private String emailAddress;
97+
98+
// Getters and setters
99+
// (Firstname, Lastname,emailAddress)-constructor and noargs-constructor
100+
// equals / hashcode
101+
}
102+
```
103+
SQL实体:
104+
105+
Sql实体:
106+
```java
107+
@Entity
108+
@Sql
109+
@Getter
110+
@Setter
111+
public class UserInfo {
112+
private String firstName;
113+
private String lastName;
114+
private String emailAddress;
115+
}
116+
```
117+
POJO DTO:
118+
```java
119+
@Getter
120+
@Setter
121+
public class UserDTO {
122+
private String firstName;
123+
private String lastName;
124+
private String emailAddress;
125+
}
126+
```
127+
128+
2、创建一个仓储接口
129+
```
130+
public interface UserRepository extends EbeanRepository<User, Long> {
131+
@Query("where emailAddress = :emailAddress order by id desc")
132+
User findUserByEmailAddressEqualsOql(@Param("emailAddress") String emailAddress);
133+
134+
/**
135+
* select fetch query细粒度控制查询字段
136+
*/
137+
@Query("select (firstname,lastname,address) fetch manager (lastname) where lastname = :lastname order by id desc")
138+
List<User> findByLastnameOql(@Param("lastname") String lastname);
139+
140+
@Query(nativeQuery = true, value = "select * from user where email_address = :emailAddress order by id desc")
141+
User findUserByEmailAddressEquals(@Param("emailAddress") String emailAddress);
142+
143+
@Query(nativeQuery = true, value = "select * from user where lastname = :lastname order by id desc")
144+
List<User> findUsersByLastnameEquals(@Param("lastname") String lastname);
145+
146+
@Query(nativeQuery = true, value = "update user set email_address = :newEmail where email_address = :oldEmail")
147+
@Modifying
148+
int changeUserEmailAddress(@Param("oldEmail") String oldEmail, @Param("newEmail") String newEmail);
149+
150+
@Query("delete from user where emailAddress = :emailAddress")
151+
@Modifying
152+
int deleteUserByEmailAddressOql(@Param("emailAddress") String emailAddress);
153+
154+
@Query(nativeQuery = true, value = "delete from user where email_address = :emailAddress")
155+
@Modifying
156+
int deleteUserByEmailAddress(@Param("emailAddress") String emailAddress);
157+
158+
/**
159+
* 命名ORM查询
160+
*/
161+
@Query(name = "withManagerById")
162+
List<User> findByLastnameNamedOql(@Param("lastname") String lastname);
163+
164+
List<User> findAllByEmailAddressAndLastname(@Param("emailAddress") String emailAddress, @Param("lastname") String lastname);
165+
}
166+
```
167+
168+
3、 对于使用到的命名sql查询、命名orm查询,编写XML文件`resources/ebean.xml`
169+
170+
```xml
171+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
172+
<ebean xmlns="http://ebean-orm.github.io/xml/ns/ebean">
173+
<entity class="org.springframework.data.ebean.sample.domain.User">
174+
<named-query name="withManagerById">
175+
<query>
176+
select (firstname,lastname,address)
177+
fetch manager (lastname)
178+
where lastname = :lastname order by id desc
179+
</query>
180+
</named-query>
181+
<raw-sql name="byEmailAddressEquals">
182+
<query>
183+
select * from user
184+
where email_address = :emailAddress
185+
order by id desc
186+
</query>
187+
</raw-sql>
188+
</entity>
189+
<entity class="org.springframework.data.ebean.sample.domain.UserInfo">
190+
<raw-sql name="userInfo">
191+
<query>
192+
select first_name, last_name, email_address from user
193+
</query>
194+
</raw-sql>
195+
<raw-sql name="userInfoByEmail">
196+
<query>
197+
select first_name, last_name, email_address from user
198+
where email_address = :emailAddress
199+
order by id desc
200+
</query>
201+
</raw-sql>
202+
</entity>
203+
</ebean>
204+
```
205+
206+
4、 编写你的使用代码:
207+
208+
`UserRepositoryIntegrationTests.java`
209+
```java
210+
@RunWith(SpringJUnit4ClassRunner.class)
211+
@ContextConfiguration(classes = SampleConfig.class)
212+
public class UserRepositoryIntegrationTests {
213+
214+
@Autowired
215+
UserRepository repository;
216+
217+
@Test
218+
public void sampleTestCase() {
219+
User user = new User("Xuegui", "Yuan", "yuanxuegui@163.com");
220+
user.setAge(29);
221+
user = repository.save(user);
222+
223+
List<User> result1 = (List<User>) repository.findAll();
224+
result1.forEach(it -> System.out.println(it));
225+
assertEquals(1, result1.size());
226+
assertEquals("Yuan", result1.get(0).getLastname());
227+
assertThat(result1, hasItem(user));
228+
229+
List<User> result2 = repository.findByLastnameOql("Yuan");
230+
assertEquals(1, result2.size());
231+
assertEquals("Yuan", result2.get(0).getLastname());
232+
assertThat(result2, hasItem(user));
233+
234+
List<User> result3 = repository.findUsersByLastnameEquals("Yuan");
235+
assertEquals(1, result3.size());
236+
assertEquals("Yuan", result3.get(0).getLastname());
237+
238+
User result4 = repository.findUserByEmailAddressEqualsOql("yuanxuegui@163.com");
239+
assertEquals("yuanxuegui@163.com", result4.getEmailAddress());
240+
241+
User result5 = repository.findUserByEmailAddressEquals("yuanxuegui@163.com");
242+
assertEquals("yuanxuegui@163.com", result5.getEmailAddress());
243+
244+
int result6 = repository.changeUserEmailAddress("yuanxuegui@163.com", "yuanxuegui@126.com");
245+
assertEquals(1, result6);
246+
247+
List<User> result7 = repository.findByLastnameOql("Yuan");
248+
assertEquals("yuanxuegui@126.com", result7.get(0).getEmailAddress());
249+
250+
int result8 = repository.deleteUserByEmailAddress("yuanxuegui@126.com");
251+
assertEquals(1, result8);
252+
253+
User result9 = repository.findUserByEmailAddressEquals("yuanxuegui@126.com");
254+
assertNull(result9);
255+
256+
user = new User("Xuegui", "Yuan", "yuanxuegui@163.com");
257+
user.setAge(29);
258+
user = repository.save(user);
259+
260+
User result10 = repository.findUserByEmailAddressEquals("yuanxuegui@163.com");
261+
assertNotNull(result10);
262+
263+
int result11 = repository.deleteUserByEmailAddressOql("yuanxuegui@163.com");
264+
assertEquals(1, result11);
265+
266+
User result12 = repository.findUserByEmailAddressEquals("yuanxuegui@163.com");
267+
assertNull(result12);
268+
}
269+
@Test
270+
public void testFindByExample() {
271+
User u = new User();
272+
u.setEmailAddress("YUANXUEGUI");
273+
List<User> result1 = repository.findAll(Example.of(u, ExampleMatcher.matchingAll()
274+
.withIgnoreCase(true)
275+
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING)));
276+
assertEquals(1, result1.size());
277+
assertEquals("Yuan", result1.get(0).getLastname());
278+
assertThat(result1, hasItem(user));
279+
280+
List<User> result2 = repository.findAll(Example.of(u, ExampleMatcher.matchingAll()
281+
.withIgnoreCase(false)
282+
.withStringMatcher(ExampleMatcher.StringMatcher.EXACT)));
283+
assertEquals(0, result2.size());
284+
}
285+
}
286+
```
287+
`EbeanQueryChannelServiceIntegrationTests.java`
288+
```java
289+
package org.springframework.data.ebean.querychannel;
290+
291+
import io.ebean.Query;
292+
import org.junit.Before;
293+
import org.junit.Test;
294+
import org.junit.runner.RunWith;
295+
import org.springframework.beans.factory.annotation.Autowired;
296+
import org.springframework.data.ebean.sample.config.SampleConfig;
297+
import org.springframework.data.ebean.sample.domain.User;
298+
import org.springframework.data.ebean.sample.domain.UserInfo;
299+
import org.springframework.data.ebean.sample.domain.UserRepository;
300+
import org.springframework.test.context.ContextConfiguration;
301+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
302+
303+
import java.util.HashMap;
304+
import java.util.Map;
305+
306+
import static org.junit.Assert.assertEquals;
307+
308+
/**
309+
* @author Xuegui Yuan
310+
*/
311+
@RunWith(SpringJUnit4ClassRunner.class)
312+
@ContextConfiguration(classes = SampleConfig.class)
313+
public class EbeanQueryChannelServiceIntegrationTests {
314+
// Test fixture
315+
User user;
316+
@Autowired
317+
private EbeanQueryChannelService ebeanQueryChannelService;
318+
@Autowired
319+
private UserRepository repository;
320+
321+
@Before
322+
public void initUser() {
323+
repository.deleteAll();
324+
user = new User("QueryChannel", "Test", "testquerychannel@163.com");
325+
user.setAge(29);
326+
user = repository.save(user);
327+
}
328+
329+
330+
@Test
331+
public void createSqlQueryMappingColumns() {
332+
String sql1 = "select first_name, last_name, email_address from user where last_name= :lastName";
333+
String sql2 = "select first_name as firstName, last_name as lastName, email_address as emailAddress from user where last_name= :lastName";
334+
Map<String, String> columnsMapping = new HashMap<>();
335+
columnsMapping.put("first_name", "firstName");
336+
columnsMapping.put("last_name", "lastName");
337+
338+
Query<UserInfo> query1 = ebeanQueryChannelService.createSqlQuery(UserInfo.class,
339+
sql1);
340+
Query<UserInfo> query2 = ebeanQueryChannelService.createSqlQuery(UserInfo.class,
341+
sql2);
342+
Query<UserInfo> query3 = ebeanQueryChannelService.createSqlQueryMappingColumns(UserInfo.class,
343+
sql1, columnsMapping);
344+
345+
query1.setParameter("lastName", "Test");
346+
query2.setParameter("lastName", "Test");
347+
query3.setParameter("lastName", "Test");
348+
UserInfo userInfo1 = query1.findOne();
349+
UserInfo userInfo2 = query2.findOne();
350+
UserInfo userInfo3 = query3.findOne();
351+
assertEquals("QueryChannel", userInfo1.getFirstName());
352+
assertEquals("testquerychannel@163.com", userInfo1.getEmailAddress());
353+
assertEquals("QueryChannel", userInfo2.getFirstName());
354+
assertEquals("testquerychannel@163.com", userInfo2.getEmailAddress());
355+
assertEquals("QueryChannel", userInfo3.getFirstName());
356+
assertEquals("testquerychannel@163.com", userInfo3.getEmailAddress());
357+
}
358+
359+
@Test
360+
public void createNamedQuery() {
361+
UserInfo userInfo = ebeanQueryChannelService.createNamedQuery(UserInfo.class,
362+
"userInfoByEmail").setParameter("emailAddress",
363+
"testquerychannel@163.com").findOne();
364+
assertEquals("QueryChannel", userInfo.getFirstName());
365+
assertEquals("testquerychannel@163.com", userInfo.getEmailAddress());
366+
}
367+
368+
@Test
369+
public void createNamedQueryWhere() {
370+
UserInfo userInfo = ebeanQueryChannelService.createNamedQuery(UserInfo.class,
371+
"userInfo").where()
372+
.eq("emailAddress", "testquerychannel@163.com").findOne();
373+
assertEquals("QueryChannel", userInfo.getFirstName());
374+
assertEquals("testquerychannel@163.com", userInfo.getEmailAddress());
375+
}
376+
377+
@Test
378+
public void createDtoQuery() {
379+
String sql = "select first_name, last_name, email_address from user where email_address = :emailAddress";
380+
UserDTO userDTO = ebeanQueryChannelService.createDtoQuery(UserDTO.class, sql)
381+
.setParameter("emailAddress", "testquerychannel@163.com")
382+
.findOne();
383+
assertEquals("QueryChannel", userDTO.getFirstName());
384+
assertEquals("testquerychannel@163.com", userDTO.getEmailAddress());
385+
}
386+
387+
}
388+
```

0 commit comments

Comments
 (0)