Persistence - shenliuyang/development GitHub Wiki

h1. Persistence

Persistence部分的练习会创建一个新的数据对象(数据库表),创建一系列存取它的Java源代码文件。

你将创建一个对象,以及一系列负责与数据库交互,持久化这个对象的类。在Java的术语中,这样的一个对象就是POJO(Plain Old Java Object),这个对象基本上可以代表数据库中的一张表,在tutorial中,有通用的泛型实现的基础DAO和Manager,基本的Dao实现了CRUD的几乎所有操作,只有当你需要用到一些复杂的数据存取操作时,才需要自定义DAO和相应的方法实现。

tutorial使用JPA作为持久层,使用了Hibernate的实现,POJO可关联到数据库的表,允许你以面向对象的方式处理,很容易进行数据对象的处理(CRUD)。

为了在tutorial工程结构中,开始创建一个新的数据对象,请完成以下几步

h2. 创建一个新的POJO,增加JPA的Annotaton

创建一个简单的Person对象,放在src/main/java/**/entity目录下,创建两个属性,firstName, lastName,

public class Person extends IdEntity {
	private String firstName;
	private String lastName;

	/**
	 用IDE生成Getter和Setter方法,以Eclipse为例,Right-click->Source->Generate Setters And Getters
	 用你的IDE生成toString(), hashCode() and equals() methods: 
	 Eclipse:
	 Right-click -> Source -> Generate toString(), hashCode(), equals()
	 */

}

扩展IdEntity是可选的,IdEntity实现了自动增长的Id策略,目前多数对应的数据库的表适用于这种ID策略, 作为推荐,同时实现toString(), equals(), hashCode()方法. 如果你打算把这个数据对象放入用户的Session中,或者通过WebService直接传递它,也应该实现Serializable接口。

当生成equals和hashCode方法时, 不要包括你的对象主键。可以参考Hibernate手册中 "Equals and Hashcode":https://community.jboss.org/wiki/EqualsAndHashCode 的说明.

首先, 添加一个@Entity的注解, 这标记了关联的表。 "name"属性是可选的; 如果未定义将使用类名. 确保你添加了 "import annotations from javax.persistence.*", 而不是导入了Hibernate的Entity.

@Entity
public class Person extends IdEntity {

可以使用@Table的Annotation改变对应到数据库的表名

@Entity
@Table(name = "xx_person")
public class Person extends IdEntity {

对于属性,在以下两种情况下要使用注解:

标记为非持久性属性 (用 @Transient)

想要改变列名或其它属性. 为了改变列名, 可以使用@Column注解. 在getFirstName() 和 getLastName() 方法上添加@Column.

@Column(name="first_name", length=50)
public String getFirstName() {
    return this.firstName;
}
...
@Column(name="last_name", length=50)
public String getLastName() {
    return this.lastName;
}
  • 避免在属性上加注解: 要注意, 属性上加注解会覆盖掉getter方法上的,在这里,我们保持在getters方法上加注解的风格.

h2. 创建数据库表

现在可以来说说怎么创建对应的数据库表了,其实你几乎什么都不需要做,在tutorial的工程里会自动创建的,在这里解释一下,免得引起疑惑。

在tutorial中使用了maven的配置,结合Hibernate的plugin,为xxx-bean中带有Entity标记的POJO在构建过程中自动创建对应的数据库表,通过maven, hibernate, spring, dbunit, junit等等工具,大大的简化了开发,单元测试的工作,规范化了流程,有兴趣的可以以后多关注一下这方面的配置知识。

如果你真的自己动手敲完了所有的代码,并且明白了此节主要内容,请看下一章节 "创建PersonDao":http://redmine.appdot.org/redmine/projects/dev-center/wiki/CreateDao

h2. 创建PersonDaoTest

在创建PersonDao之前先创建PersonDaoTest,这种方式就叫做Test-Driven Development(测试驱动开发),这种方式更易于开发出高质量的软件,尝试一下,这会让我们受益良多。

首先,我们要创建一个PersonDaoTest.java的文件,放于在src/test/java/**/dao的目录,这个类继承自BaseDaoJpaTestCase,这个基类帮你加载了所需的所有SpringContext,方便你编写单元测试的代码。

/**
 * PersonDao的测试用例, 测试ORM映射及特殊的DAO操作.
 * 
 * 默认在每个测试函数后进行回滚.
 * 
 * @author liand
 */
public class PersonDaoTest extends BaseJpaDaoTestCase {

	@Autowired
	private PersonDao entityDao;

	@Test
	//如果你需要真正插入数据库,将Rollback设为false
	//@Rollback(false) 
	public void crudEntityWithRole() {
		//新建并保存带权限组的用户
		Person person = new Person();
		person.setFirstName("testFirstName");
		person.setLastName("testLastName");
		entityDao.save(person);
		flush();

		//获取用户
		person = entityDao.findOne(person.getId());
		assertEquals("testLastName", person.getLastName());
		assertEquals("testFirstName", person.getFirstName());

		//删除用户
		entityDao.delete(person.getId());
		flush();

		person = entityDao.findOne(person.getId());
		assertNull(person);
	}

	@Test
	public void testFindPersonByFirstName() throws Exception {
		List people = entityDao.findByFirstName("Lian");
		assertTrue(people.size() > 0);
	}

}

上面是一个实现了PersonDao的基本CRUD测试的单元测试用例,实际使用的测试用例会有更多的测试方法,但上面这个基本的测试用例可以帮助我们快速理解这个过程。

你应该注意到了,测试用例中使用了预置的数据,因为appdot建立的工程中集成了DbUnit的支持,因此还可以使用预定义的数据,DbUnit的Maven插件会在测试运行前建立数据库,灌入预置的数据,你只需要简单的编辑tutorial-data模块下的src/test/resources/sample-data.xml文件,就可由maven完成一整套自动化的流程。

	
	

h2. 创建PersonDao

在创建PersoDao这一节,你会发现无比的简单,基本上你只需要定义一个PersonDao的接口,继承支持泛型的BaseJpaRepository

/**
 * 人对象的Dao interface.
 * 
 * @author liand
 */
public interface PersonDao extends IdEntityRepository {

这样你就拥有了支持基本CRUD操作的PersonDao,如果你需要使用更多的finders(查询方法),你只需要在接口中定义附加的方法

/**
 * 人对象的Dao interface.
 * 
 * @author liand
 */
public interface PersonDao extends IdEntityRepository {
	List findByFirstName(String firstName);
}

不需要再做任何实现,即可拥有findByFirstName,这一切源于我们使用了spring-data-jpa,不仅简单的查询,复杂的组合查询也同样能够实现,它是通过接口中定义的方法的名字,使用习惯大于配置的思想实现的,具体可参考spring-data-jpa的手册。

这可以将我们从书写无聊的sql中解脱出来,当然也同样支持自定义的实现,在spring-data-jpa中有自定义实现的完整参考,此处暂时不做赘述。

h2. 运行PersonDaoTest

使用"mvn test -Dtest=PersonDaoTest"尝试运行你上面敲出来的单元测试吧。

⚠️ **GitHub.com Fallback** ⚠️