首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

Spring Data JPA 札记

2013-02-19 
Spring Data JPA 笔记package com.esom.tech.springjpa.domainimport javax.persistence.Columnimport j

Spring Data JPA 笔记
package com.esom.tech.springjpa.domain;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.SequenceGenerator;import javax.persistence.Table;import org.hibernate.annotations.DynamicInsert;import org.hibernate.annotations.DynamicUpdate;@Entity@DynamicInsert @DynamicUpdate //生成的SQL中涉及的字段只包含User类中修改的属性所对应的表字段@Table(name="MA_USER")public class User {@Id@Column(name = "ID") @SequenceGenerator(name="USER_ID_GENERATOR", sequenceName="SEQ_USER_ID",allocationSize=1)@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="USER_ID_GENERATOR")private Long id;/** * 如果不指定表字段,会自动映射为USERNAME * 并且在加载运行时,发现没有该表字段,会自动添加创建(如果表,Sequence没有也会创建)。 * 对应ORACLE,创建的的类型对应关系: * String VARCHAR2(255 CHAR) * LongNUMBER(19) * Integer NUMBER(10) * java.sql.DateDATE * java.sql.TimeDATE * java.util.DateTIMESTAMP(6) * java.sql.TimestampTIMESTAMP(6) */@Column(name = "USER_NAME", unique = true) private String userName;@Column(name = "FIRST_NAME")private String firstName;@Column(name = "LAST_NAME")private String lastName;@Column(name = "AGE")private Integer age;@Overridepublic String toString() {return String.format("Entity of type %s with id: %s", this.getClass().getName(), getId());}@Overridepublic boolean equals(Object obj) {if (null == obj) {return false;}if (this == obj) {return true;}if (!getClass().equals(obj.getClass())) {return false;}return null == this.getId() ? false : this.getId().equals(((User)obj).getId());}// 忽略所有get、set方法}

?

2. Repository接口

package com.esom.tech.springjpa.repository;import java.util.List;import org.springframework.data.jpa.repository.JpaSpecificationExecutor;import org.springframework.data.jpa.repository.Query;import org.springframework.data.repository.CrudRepository;import org.springframework.data.repository.query.Param;import com.esom.tech.springjpa.domain.User;public interface UserRepository extends CrudRepository<User, Long>, JpaSpecificationExecutor<User>{/** * 根据方法名解析 * @param lastname * @return */List<User> findByLastName(String ln);/** * 根据@Query和命名参数解析 * 注意这里是HSQL,所以用User(而非ma_user), lastName(而非first_name) * @param name * @return */@Query(" from User u where u.firstName = :name or u.lastName = :name ")public List<User> findByFirstNameOrLastName(@Param("name") String name);/** * 根据@Query和占位符解析 * @param firstname * @return */@Query(" from User u where u.firstName = ?1 and lastName = ?2 ")List<User> findByFirstNameAndLastName(String fb, String ln);}

?

3. 一小陀配置

?

配置repository和服务bean,demo-repository-context.xml

<?xml version="1.0" encoding="UTF8"?><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:jpa="http://www.springframework.org/schema/data/jpa"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"><import resource="classpath*:/META-INF/spring/application-context-root.xml" /><!--配置jpa repository,核心部分--><jpa:repositories base-package="com.esom.tech.springjpa.repository" entity-manager-factory-ref="entityManagerFactory"transaction-manager-ref="transactionManager" />  <!--配置服务bean--><context:component-scan base-package="com.esom.tech.springjpa.service"/></beans>

?

配置数据源及EntityManager,application-context-root.xml

<?xml version="1.0" encoding="UTF8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!--Data Source--><bean id="dataSource" destroy-method="close"><property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" /><property name="url" value="jdbc:oracle:thin:@171.22.70.28:1521:gbst" /><property name="username" value="username" /><property name="password" value="password" /><property name="initialSize" value="1"/><property name="maxActive" value="2"/></bean><!-- Parent Entity Manager : Hibernate 实现 --><bean id="parentEntityManagerFactory" value="ORACLE" /><property name="showSql" value="true" /><property name="generateDdl" value="true" /></bean></property></bean><!-- Entity Manager --><bean id="entityManagerFactory" parent="parentEntityManagerFactory"><property name="dataSource" ref="dataSource" /><property name="packagesToScan"><array><!--entity扫描目录,可多个value节点--><value>com.esom.tech.springjpa.domain</value></array></property></bean><!-- Transaction Manager --><bean id="transactionManager" ref="entityManagerFactory" /></bean><tx:advice id="businessTxAdvise" transaction-manager="transactionManager" /><aop:config><aop:pointcut id="businessPointcut"expression="execution(* com.esom.tech..*.*(..))" /><aop:advisor advice-ref="businessTxAdvise" pointcut-ref="businessPointcut" /></aop:config></beans>

?根据项目具体情况配置,不一定是Hibernate EntityManager及ORACLE

?

4. 业务层接口

package com.esom.tech.springjpa.service;import com.esom.tech.springjpa.domain.User;public interface UserService {//保存Userpublic User saveUser(User user);//是否存在客户boolean hasUser(Long id);}

?

5. 业务层接口实现类

package com.esom.tech.springjpa.service.impl;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.esom.tech.springjpa.domain.User;import com.esom.tech.springjpa.repository.UserRepository;import com.esom.tech.springjpa.service.UserService;@Servicepublic class UserServiceImpl implements UserService{@Autowiredprivate UserRepository userRepository;public boolean hasUser(Long id) {User user = userRepository.findOne(id);return user != null ? true:false;}public User saveUser(User user) {return userRepository.save(user);}}

?

6. 测试代码

package com.esom.tech.springjpademo;import static org.junit.Assert.*;import java.util.List;import javax.persistence.criteria.CriteriaBuilder;import javax.persistence.criteria.CriteriaQuery;import javax.persistence.criteria.Predicate;import javax.persistence.criteria.Root;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.jpa.domain.Specification;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;//import org.springframework.test.context.transaction.TransactionConfiguration;//import org.springframework.transaction.annotation.Transactional;import com.esom.tech.springjpa.domain.User;import com.esom.tech.springjpa.repository.UserRepository;import com.esom.tech.springjpa.service.UserService;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = {"classpath*:/META-INF/spring/springjpa/demo-repository-context.xml" })//@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)//@Transactionalpublic class SpringJpaTest {@AutowiredUserRepository repository;@AutowiredUserService userService;User user;//每个@Test方法都会先执行init()一遍@Beforepublic void init(){user = new User();user.setAge(28);user.setFirstName("Lios");user.setLastName("Lin");user.setUserName("Lios Lin");}// crud方法测试 @Testpublic void testCrud(){//第一次,新增一条记录,新增后user.id会给赋值repository.save(user);//第二次,不做保存,因为user.id有值,会根据user.id查询数据库是否存在记录,对有记录并且字段值没变动的忽略保存操作repository.save(user); //第三次,字段值有变动(包括置为null),做更新保存user.setAge(68);repository.save(user); User user2 = repository.findOne(user.getId());assertEquals(user.getAge(),user2.getAge());assertEquals(user,user2);}// method query测试@Testpublic void testMethodQuery() throws Exception {repository.save(user);List<User> users = repository.findByLastName("Lin");assertNotNull(users);assertTrue(users.contains(user));}// named query测试@Testpublic void testNameQuery() throws Exception {repository.save(user);List<User> users = repository.findByFirstNameOrLastName("Lin");assertTrue(users.contains(user));}// criteria query测试@Testpublic void testCriteriaQuery() throws Exception {repository.save(user);List<User> users = repository.findAll(new Specification<User>() {public Predicate toPredicate(Root<User> root,CriteriaQuery<?> query,CriteriaBuilder cb) {return cb.equal(root.get("lastName"), user.getLastName());}});assertTrue(users.contains(user));}// 其他 query测试@Testpublic void testOtherQuery() throws Exception {repository.save(user);//占位符查询List<User> users = repository.findByFirstNameAndLastName(user.getFirstName(), user.getLastName());assertTrue(users.contains(user));}// service测试@Testpublic void testService() throws Exception {userService.saveUser(user);assertTrue(userService.hasUser(user.getId()));}}

?

这个项目结构如下(附件一并带上源码):

?
Spring Data JPA 札记

?

跑JUnit测试,绿了,要使生活过的去,哪怕测试有点绿,,,

至于pom.xml为什么是红呢,这是因为maven引用oracle jdbc驱动引起的,下面章节5会说到。?

?

?4、Repository核心接口

上面代码可以看到持久层UserRepository继承了CrudRepository和JpaSpecificationExecutor接口(注意这些接口都不需要实现),而CrudRepository又继承了顶级接口Repository。

?

我们看下接口CrudRepository中的办法:

public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {<S extends T> S save(S entity);<S extends T> Iterable<S> save(Iterable<S> entities);T findOne(ID id);boolean exists(ID id);Iterable<T> findAll();Iterable<T> findAll(Iterable<ID> ids);long count();void (ID id);void (T entity);void (Iterable<? extends T> entities);void All();}

继承Repository,实现了一组CRUD相关的方法。

?

其他核心接口说明:

PagingAndSortingRepository: 继承CrudRepository,实现了一组分页排序相关的方法

JpaRepository: 继承PagingAndSortingRepository,实现一组JPA规范相关的方法

JpaSpecificationExecutor: 比较特殊,不属于Repository体系,实现一组JPA Criteria查询相关的

这些接口都不需要写任何实现类,Spring Data Jpa框架帮你搞定这一切。

?

?另外说下UserRepository的一些query的其他用法:

1)Method Query: 方法级别的查询,针对?
?
?

2)Named Query: 针对一些复杂的SQL,支持原生SQL方式,进行查询,保证性能
3)Criteria Query: 支持JPA标准中的Criteria Query

4)@Modifying 将查询标识为修改查询

@Modifying  @Query("update User a set a.age = ?1 where a.id = ?2")  public int updateUserAge(int age, int id);

?

?

5、示例构建过程遇到的一些问题

1、使用maven管理项目包的依赖,如果项目没用到maven,根据pom.xml的配置引用对应包到项目

<project>...  <properties>    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring.version>3.2.0.RELEASE</spring.version><slf4j.version>1.6.6</slf4j.version>  </properties>  <dependencies>  <!-- JUnit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.7</version><scope>test</scope></dependency><!-- J2EE --><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope></dependency><dependency><groupId>javax.transaction</groupId><artifactId>jta</artifactId><version>1.1</version><scope>provided</scope></dependency><!-- spring --><dependency><groupId>org.springframework</groupId><artifactId>spring-orm</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-jpa</artifactId><version>1.2.0.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>${spring.version}</version></dependency><!--dbcp--><dependency><groupId>commons-dbcp</groupId><artifactId>commons-dbcp</artifactId><version>1.4</version></dependency><!-- HSQL<dependency><groupId>org.hsqldb</groupId><artifactId>hsqldb</artifactId><version>2.0.0</version><scope>test</scope></dependency> --> <!-- hibernate --><dependency><groupId>org.hibernate.javax.persistence</groupId><artifactId>hibernate-jpa-2.0-api</artifactId><version>1.0.0.Final</version></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-entitymanager</artifactId><version>4.1.6.Final</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>${slf4j.version}</version><scope>runtime</scope></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.7.1</version></dependency><!--oracle--><dependency><groupId>com.oracle</groupId><artifactId>ojdbc6</artifactId><version>11.2.0.3.0</version></dependency>  </dependencies>...</project>

?

?

2、用Maven管理Oracle? JDBC驱动包有点特殊。直接声明依赖,pom.xml文件会提示找不到依赖,这是因为Oracle JDBC驱动包是需要Oracle官方授权才能从Maven中央库下载,我们可以通过2种方法解决:

?

第一种:首先,下载Oracle的jdbc驱动包ojdbc6.jar,

下载地址:http://www.oracle.com/technetwork/database/features/jdbc/index-091264.html,

这里下载的版本是11.2.0.1.0。

然后,通过命令行执行命令将包安装本地库中去:mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.1.0 -Dpackaging=jar -Dfile=D:\ojdbc6.jar。

最后,在pom.xml声明依赖

<project>  ...  <repositories>    <repository><id>my-repo</id><name>my-repo</name><url>http://localhost:8082/nexus/content/groups/public</url></repository>  </repositories>  <dependencies>...<!--oracle--><dependency><groupId>com.oracle</groupId><artifactId>ojdbc6</artifactId><version>11.2.0.3.0</version></dependency>...  </dependencies>   ... </project>

?

JDBC驱动就添加到工程中了。

?

第二种:通过构建自己的私人仓库实现,后续介绍。