Spring Data加JPA (Maven构建Java工程)

来源:互联网 发布:怎么在mac上新建文件夹 编辑:程序博客网 时间:2024/06/04 22:19

  使用Maven构建一Java项目,起名springdata

一 基本工作


1,1  配置pom文件

1.1.1 导入6项依赖


1.1.2 在pom.xml文件中配置jdk版本为1.8

<build>      <plugins>          <plugin>              <groupId>org.apache.maven.plugins</groupId>              <artifactId>maven-compiler-plugin</artifactId>              <configuration>                  <source>1.8</source>                  <target>1.8</target>                  <encoding>UTF-8</encoding>              </configuration>          </plugin>      </plugins>  </build> 

1.2 配置spring全局配置文件


1.2.1  在src/main/resources 下创建 db.properties文件

jdbc.driverClass=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql:///jpajdbc.username=rootjdbc.password=root

1.2.2  在src/main/resouces 下创建spring全局配置文件 applicationContext.xml

创建文件时,命名空间选择如下


applicationContext.xml详情:

<?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:context="http://www.springframework.org/schema/context"xmlns:jpa="http://www.springframework.org/schema/data/jpa"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsdhttp://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"><!-- 导入数据库的配置信息,注意这个标签只能出现一次, 导入一个匹配文件  若想导入多个配置文件可以将 db.properties写成 *.properties--><context:property-placeholder location="classpath:db.properties"/><!-- 扫包(让spring扫描含有注解类:service注解),扫描包的目的是为了创建对象 --><context:component-scan base-package="com.qx.springdata"></context:component-scan><!-- 配置JPA要用到的dataSource --><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driverClass}"></property><property name="jdbcUrl" value="${jdbc.url}"></property><property name="user" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 配置 entityManagerFactory--><bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"><property name="dataSource" ref="dataSource"></property><!-- 配置jpa的具体实现 --><property name="jpaVendorAdapter"><bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean></property><!-- 配置扫描包,扫描所有带有jpa注解的类(就是entity注解) --><property name="packagesToScan" value="com.qx.springdata"></property><!-- 配置具体实现的相关配置(因为指定了具体实现是hibernate,因此也需要为hibernate进行相关的配置) --><!-- JPA和JDBC一样是规范,你需要给它指定一个具体的实现 --><property name="jpaProperties"><props><prop key="hibernate.show_sql">true</prop><prop key="hibernate.format_sql">true</prop><prop key="hibernate.hbm2ddl.auto">update</prop></props></property></bean><!-- 配置事务管理器 --><bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"><property name="entityManagerFactory" ref="entityManagerFactory"></property></bean><!-- 注解驱动:扫描带有@Transaction注解的类或方法 --><tx:annotation-driven transaction-manager="transactionManager"/><!-- 配置扫描springdata 扫描的是继承自Repository接口的接口 (接口可以多继承) 目的:扫描jpa注解 --><jpa:repositories base-package="com.qx.springdata" entity-manager-factory-ref="entityManagerFactory"></jpa:repositories></beans>

2.1 创建持久化类和 SpringData的核心接口Repository的子接口


SpringData_Repository接口概述

  • Repository 接口是 Spring Data 的一个核心接口,它是一个空接口,不提供任何方法(和Serializable一样,Serializable也是一个空接口),开发者需要在自己定义的接口中声明需要的方法  public interface Repository<T, ID extends Serializable> { } 

  • Spring Data可以让我们只定义接口,只要遵循 Spring Data的规范,就无需写实现类。
  • 与继承 Repository 等价的一种方式,就是在持久层接口上使用 @RepositoryDefinition 注解,并为其指定 domainClass 和 idClass 属性。

  • Repository 的子接口

    • 基础的 Repository 提供了最基本的数据访问功能,其几个子接口则扩展了一些功能。它们的继承关系如下:

    1.Repository: 仅仅是一个标识,表明任何继承它的均为仓库接口类

    2.CrudRepository: 继承 Repository,实现了一组 CRUD 相关的方法

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

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

    5.自定义的 XxxxRepository 需要继承 JpaRepository,这样的 XxxxRepository 接口就具备了通用的数据访问控制层的能力。

    6.JpaSpecificationExecutor: 不属于Repository体系,实现一组 JPA Criteria 查询相关的方法

命名规范:

LessThan,GreaterThan 指的是数字
After,Before指的是日期 Date
写错会提示


2.1.1 创建持久化类Person

package com.qx.springdata;import java.util.Date;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.Table;@Entity@Table(name="jpa_persons")public class Person {private Integer id;private String lastName;private String email;private Date birth;@GeneratedValue  // 按照数据库默认的方式进行自增@Idpublic Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public Date getBirth() {return birth;}public void setBirth(Date birth) {this.birth = birth;}}

2.1.2 创建Repository的子接口PersonRepository(继承关系)

package com.qx.springdata;import org.springframework.data.repository.Repository;/** * 操作person类的接口 * 需要继承自Repository * 参1: 代表当前操作的实体类 * 参2: 代表实体类的主键类型 * @author dell * *Repository是springdata的核心接口,这个接口的实现规定了spring data操作数据库的规范--命名规范 *查询是以get或者是find或者是read开头 */public interface PersonRepository extends Repository<Person, Integer> {Person getByLastName(String lastName);}

3.1 创建测试类, 自动生成数据库表

3.1.1 创建一测试类TestSpringData

package com.qx.springdata.test;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.qx.springdata.PersonRepository;public class TestSpringData {private ApplicationContext context;private PersonRepository personRepository;@org.junit.Before  //该注解含义在执行@Test注解之前先执行这个代码public void Before(){context=new ClassPathXmlApplicationContext("applicationContext.xml");personRepository=context.getBean(PersonRepository.class);System.out.println("测试前");}@Testpublic void testHellord(){//Person person = personRepository.getByLastName("bb");//System.out.println(person);}}

3.1.2 运行testHellord方法,生成数据库表

运行前:数据库jpa是空的

运行后: 自动生成了 表 jpa_persons (生成了两种表,且jpa_persons这种表主键并不是自增的)



注意:

生成了两张表,且jpa_persons这种表主键并不是自增的, 跟持久化类id的注解@GeneratedValue 有关


当注解是

  

@GeneratedValue  // 按照数据库默认的方式进行自增@Idpublic Integer getId() {return id;}
或是

@GeneratedValue(strategy=GenerationType.AUTO)  // 按照数据库默认的方式进行自增@Idpublic Integer getId() {return id;}
时,都将会生成两张表,其中一个是hibernate_sequence,且表jpa_persons的主键并非自增

只有为下面这种注解方式时,才会只生成一张表,且jpa_persons表的主键id是自增的

@GeneratedValue(strategy=GenerationType.IDENTITY)  // 按照指定的方式进行自增@Idpublic Integer getId() {return id;}

验证:

package com.qx.springdata;import java.util.Date;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.Table;@Entity@Table(name="jpa_persons")public class Person {private Integer id;private String lastName;private String email;private Date birth;@GeneratedValue(strategy=GenerationType.IDENTITY)  // 按照指定的方式进行自增@Idpublic Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public Date getBirth() {return birth;}public void setBirth(Date birth) {this.birth = birth;}@Overridepublic String toString() {return "Person [id=" + id + ", lastName=" + lastName + ", email=" + email + ", birth=" + birth + "]";}}



自动生成的表:



二 正式操作 ,CRUD

2.1 单表单对象

往jpa_persons表中插入几条数据,以便测试:




在PersonRepository接口中按命名规范,定义方法:

/** * 操作person类的接口 * 需要继承自Repository * 参1: 代表当前操作的实体类 * 参2: 代表实体类的主键类型 * @author dell * *Repository是springdata的核心接口,这个接口的实现规定了spring data操作数据库的规范--命名规范 *查询是以get或者是find或者是read开头 */public interface PersonRepository extends Repository<Person, Integer> {//根据名字查找Person getByLastName(String lastName);//查询名字以xxx开头同时id小于xxx的值List<Person> getByLastNameStartingWithAndIdLessThan(String lastName,Integer id);List<Person> getByLastNameEndingWithAndIdLessThan(String lastName,Integer id);//查询对应邮件的人List<Person> getByEmailIn(List<String> emails);//查询邮件在对应里面里面且id小于某个值的人List<Person> getByEmailInAndIdLessThan(List<String> emails,Integer id);}

测试类中进行测试

public class TestSpringData {private ApplicationContext context;private PersonRepository personRepository;@org.junit.Before  //该注解含义在执行@Test注解之前先执行这个代码public void Before(){context=new ClassPathXmlApplicationContext("applicationContext.xml");personRepository=context.getBean(PersonRepository.class);System.out.println("测试前");}@Testpublic void testHellord(){Person person = personRepository.getByLastName("张三");System.out.println(person);}@Testpublic void testKeyWords(){//List<Person> list = personRepository.getByLastNameStartingWithAndIdLessThan("张", 8);//System.out.println(list);//List<Person> list = personRepository.getByLastNameEndingWithAndIdLessThan("c", 8);//System.out.println(list);//使用 Arrays.asList(T... a)可以把传进来的一个可变参数数组快速转变成集合List<Person> list = personRepository.getByEmailIn(Arrays.asList("bb@163.com","cc@163.com","zs@163.com"));System.out.println(list);List<Person> list2=personRepository.getByEmailInAndIdLessThan(Arrays.asList("bb@163.com","cc@163.com","zs@163.com"), 6);System.out.println(list2);}}


测试testKeyWords结果:底层执行的sql语句和查询结果:

INFO: HHH000228: Running hbm2ddl schema update测试前七月 30, 2017 11:17:24 下午 org.hibernate.hql.internal.QueryTranslatorFactoryInitiator initiateServiceINFO: HHH000397: Using ASTQueryTranslatorFactoryHibernate:     select        person0_.id as id1_0_,        person0_.birth as birth2_0_,        person0_.email as email3_0_,        person0_.lastName as lastName4_0_     from        jpa_persons person0_     where        person0_.email in (            ? , ? , ?        )[Person [id=2, lastName=bb, email=bb@163.com, birth=2017-07-01 19:31:44.0], Person [id=3, lastName=cc, email=cc@163.com, birth=2017-07-09 22:24:17.0], Person [id=6, lastName=张三, email=zs@163.com, birth=2017-07-29 22:25:45.0]]Hibernate:     select        person0_.id as id1_0_,        person0_.birth as birth2_0_,        person0_.email as email3_0_,        person0_.lastName as lastName4_0_     from        jpa_persons person0_     where        (            person0_.email in (                ? , ? , ?            )        )         and person0_.id<?[Person [id=2, lastName=bb, email=bb@163.com, birth=2017-07-01 19:31:44.0], Person [id=3, lastName=cc, email=cc@163.com, birth=2017-07-09 22:24:17.0]]


2.2 关联表,查询关联数据

2.2.1新建一实体类 Address

package com.qx.springdata;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.Table;/** * 给类同时加@Entity 和 @Table的原因: * 当你从数据库读取数据时,由于你要读取的表映射有实体类(@Entity注解的),那么后台会自动帮你 * 实例化一个对象: * 创建一个Entity Bean对象相当于新建一条记录,删除一个Entity Bean对象会同时从数据库中删除 * 对应记录,修改一个Entity Bean时,容器会自动将Entity Bean的状态和数据库同步. * @author dell * */@Entity  //该注解用于指明这是一个实体bean@Table(name="jpa_addresses") //该注解用于指明Entity所要映射到的数据库表public class Address {private Integer id;private String provience;private String city;@GeneratedValue(strategy=GenerationType.IDENTITY)@Idpublic Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getProvience() {return provience;}public void setProvience(String provience) {this.provience = provience;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}@Overridepublic String toString() {return "Address [id=" + id + ", provience=" + provience + ", city=" + city + "]";}}


2.2.2 在Person类中增加一属性 Address并设置getter setter方法

private Address address;@JoinColumn(name="address_id")  //该注解用来修饰代表关联实体的属性,用于映射底层的外键列@ManyToOne  //一个地址对应着多个人,人和地址之间多对一的关系public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}

2.2.3 在PersonRepository接口中按照命名规范,新定义一方法

List<Person> getByAddressIdGreaterThan(Integer addressId);

2.2.4 在测试类中,添加测试方法testKeyWords2

//查询关联数据@Testpublic void testKeyWords2(){List<Person> list = personRepository.getByAddressIdGreaterThan(110);System.out.println(list);}

运行该测试方法.会发现自动生成了表jpa_addresses, 且jpa_persons自动多了一外键列address_id


使用关联数据进行查询时,底层自动走的左外连接



注意:定义方法时要注意:

List<Person> getByAddressIdGreaterThan(Integer addressId);

在定义方法时,如果对象中存在这个属性addressId,会优先使用自带的属性而不是关联数据


在Person类中增加一属性addressId, 设置getter setter方法

而Person类中有一关联属性Address,那么这次去调用方法

List<Person> getByAddressIdGreaterThan(Integer addressId);时,

会优先使用自带的属性AddressId

如果想用关联数据的,而里面刚好有一个属性是同名的,那么你需要加一个下划线分割一下.

List<Person> getByAddress_IdGreaterThan(Integer addressId);  使用_后,代表Address的id


接口中同时定义两个方法

List<Person> getByAddressIdGreaterThan(Integer addressid);//注意,如果对象中存在这个属性,会优先使用自带的属性而不是关联数据List<Person> getByAddress_IdGreaterThan(Integer addressid);

测试类的测试方法:

//查询关联数据@Testpublic void testKeyWords2(){List<Person> list = personRepository.getByAddressIdGreaterThan(110);System.out.println(list);List<Person> list2=personRepository.getByAddress_IdGreaterThan(110);System.out.println(list2);}

运行测试方法,底层走的查询语句: