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

  使用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.Driver
jdbc.url=jdbc:mysql:///jpa
jdbc.username=root
jdbc.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.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd
		http://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  // 按照数据库默认的方式进行自增
	@Id
	public 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("测试前");
	}
	
	@Test
	public 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  // 按照数据库默认的方式进行自增
	@Id
	public Integer getId() {
		return id;
	}
或是

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

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

	@GeneratedValue(strategy=GenerationType.IDENTITY)  // 按照指定的方式进行自增
	@Id
	public 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)  // 按照指定的方式进行自增
	@Id
	public 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;
	}
	
	@Override
	public 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("测试前");
	}
	
	@Test
	public void testHellord(){
		Person person = personRepository.getByLastName("张三");
		System.out.println(person);
		
	}
	
	@Test
	public 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 initiateService
INFO: HHH000397: Using ASTQueryTranslatorFactory
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 (
            ? , ? , ?
        )
[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)
	@Id
	public 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;
	}
	@Override
	public 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

	//查询关联数据
	@Test
	public 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);

测试类的测试方法:

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

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





  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值