在Spring Data JPA中,对于定义符合规范的Dao层接口,我们只需要遵循以下几点就可以了:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" 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.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="root">property>
<property name="password" value="lemon">property>
<property name="url" value="jdbc:mysql:///db_hibernate" >property>
<property name="driverClassName" value="com.mysql.jdbc.Driver">property>
bean>
<bean id="entityManagerFactoty" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="cn.lemon.domain" />
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false" />
<property name="database" value="MYSQL" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
<property name="showSql" value="true" />
bean>
property>
<property name="jpaDialect" >
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
property>
bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoty">property>
bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
<aop:config proxy-target-class="true">
<aop:pointcut id="pointcut" expression="execution(* cn.lemon.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut" />
aop:config>
<jpa:repositories base-package="cn.lemon.dao" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactoty">jpa:repositories>
beans>
package cn.lemon.domain;
import javax.persistence.*;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "customer_")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_")
private Integer id;
@Column(name = "CUST_NAME_")
private String custName;
@Column(name = "TELEPHONE_")
private String telephone;
@Column(name = "CREATE_DATE_")
private Date createDate;
@Column(name = "SEND_DATE_")
private Date sendDate;
@Column(name = "type_")
private String type;
@OneToMany(mappedBy = "customer")
private Set<Order> orders = new HashSet<>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Date getSendDate() {
return sendDate;
}
public void setSendDate(Date sendDate) {
this.sendDate = sendDate;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}
package cn.lemon.domain;
import javax.persistence.*;
@Entity
@Table(name = "order_")
public class Order {
@Id
@Column(name = "id_")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "PRODUCT_NAME_")
private String productName;
@Column(name = "PRICE_")
private Double price;
@Column(name = "NUM_")
private Integer num;
@ManyToOne
@JoinColumn(name = "customer_id_")
private Customer customer;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
package cn.lemon.dao;
import cn.lemon.domain.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface CustomerDao extends JpaRepository<Customer, Integer>, JpaSpecificationExecutor<Customer> {
}
package cn.lemon.dao;
import cn.lemon.domain.Order;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface OrderDao extends JpaRepository<Order, Integer>, JpaSpecificationExecutor<Order> {
}
package cn.lemon.dao;
import cn.lemon.domain.Customer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/beans.xml")
public class CustomerDaoTest {
@Autowired
private CustomerDao customerDao;
@Test
public void testAdd() {
Customer c = new Customer();
c.setCustName("李三");
c.setType("大客户");
customerDao.save(c);
}
}
JpaRepository
和JpaSpecificationExecutor
接口,这样就可以使用这些接口中定义的方法,但是这些方法都只是一些声明,没有具体的实现方式,那么在 Spring Data JPA中它又是怎么实现的呢?在继承JpaRepository,和JpaRepository接口后,我们就可以使用接口中定义的方法进行查询,继承JpaRepository后的方法列表:
继承JpaSpecificationExecutor的方法列表:
修改 CustomerDao.java 接口
package cn.lemon.dao;
import cn.lemon.domain.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface CustomerDao extends JpaRepository<Customer, Integer>, JpaSpecificationExecutor<Customer> {
// @Query("select * from customer_ where cust_name_ like '%s%' and type_ = '大客户'")
@Query("from Customer where custName like ?1 and type = ?2")
public List<Customer> findAllCustomer(String custName, String type);
}
测试类
package cn.lemon.dao;
import cn.lemon.domain.Customer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/beans.xml")
public class JpqlDaoTest {
@Autowired
private CustomerDao customerDao;
@Test
public void testFindAllCustomer() {
List<Customer> list = customerDao.findAllCustomer("%a%", "大客户");
for (Customer customer : list) {
System.out.println(customer.getCustName() + " " + customer.getType());
}
}
}
修改 CustomerDao.java 接口
package cn.lemon.dao;
import cn.lemon.domain.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
public interface CustomerDao extends JpaRepository<Customer, Integer>, JpaSpecificationExecutor<Customer> {
/**
* @Query:代表是是进行查询,声明此方法是用来更新操作
* @Modifying:当前执行的是一个更新操作
*/
@Query("update Customer set type = ?1 where type = ?2")
@Modifying
public void updateType(String type1, String type2);
}
测试类
package cn.lemon.dao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/beans.xml")
public class JpqlDaoTest {
@Autowired
private CustomerDao customerDao;
/**
* rollback = false:测试时因为自动回滚,false表示不会滚
*/
@Test
@Transactional
@Rollback(false)
public void testUpdateType() {
customerDao.updateType("超大客户", "大客户");
}
}
package cn.lemon.dao;
import cn.lemon.domain.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.List;
public interface CustomerDao extends JpaRepository<Customer, Integer>, JpaSpecificationExecutor<Customer> {
/**
* 方法命名规则查询
* 前缀(findBy)+ 属性(CustName)+ 查询方式(Like)+ 连接符(And)+ 属性(Type)+ 方式(Equals)......
*/
public List<Customer> findByCustNameLikeAndTypeEquals(String custName, String type);
}
测试类
package cn.lemon.dao;
import cn.lemon.domain.Customer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/beans.xml")
public class JpqlDaoTest {
@Autowired
private CustomerDao customerDao;
@Test
public void testFind2() {
List<Customer> list = customerDao.findByCustNameLikeAndTypeEquals("%a%", "超大客户");
for (Customer customer : list) {
System.out.println(customer.getCustName() + " " + customer.getType());
}
}
}
在测试类中添加分页查询
package cn.lemon.dao;
import cn.lemon.domain.Customer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/beans.xml")
public class JpqlDaoTest {
@Autowired
private CustomerDao customerDao;
/**
* 分页查询
*/
@Test
public void testFindPage() {
//参数1:页码
//参数2:每页行数
Pageable pageable = PageRequest.of(0, 5);
Page<Customer> page = customerDao.findAll(pageable);
System.out.println("数据=" + page.getContent());
System.out.println("总页数=" + page.getTotalPages());
System.out.println("总行数=" + page.getTotalElements());
}
}
package cn.lemon.dao;
import cn.lemon.domain.Customer;
import cn.lemon.domain.Order;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/beans.xml")
public class SpecificationQueryTest {
@Autowired
private CustomerDao customerDao;
@Autowired
private OrderDao orderDao;
/**
* specification查询等同于criteria查询,在匿名内部类中返回criteriaBuilder构建的条件
* 具体criteria查询,参考qbc查询
* root:Root接口,代表查询的根对象,可以通过root 获取实体类中的属性
* query: 代表顶层的查询对象,用来自定义查询
* cb:用来构建查询,此对象里有很多查询方法
*/
@Test
public void testSpecification1() {
List<Customer> list = customerDao.findAll((root, query, builder) -> {
Predicate p1 = builder.like(root.get("custName"), "%a%");
Predicate p2 = builder.like(root.get("type"), "超大客户");
return builder.and(p1, p2);
});
for (Customer customer : list) {
System.out.println(customer.getCustName() + " " + customer.getType());
}
}
/**
* specification分页查询
*/
@Test
public void testSpecification2() {
Pageable pageable = PageRequest.of(0,2);
Page<Customer> page = customerDao.findAll((root, query, builder) -> {
List<Predicate> list = new ArrayList<>();
// //动态查询
// if (true) { //条件成立
// list.add(builder.like(root.get("custName"), "%a%"));
// }
// if (true) { //条件成立
// list.add(builder.like(root.get("type"), "超大客户"));
// }
// Predicate[] predicates = (Predicate[]) list.toArray();
// return builder.and(predicates);
Predicate p1 = builder.like(root.get("custName"), "%a%");
Predicate p2 = builder.like(root.get("type"), "超大客户");
return builder.and(p1, p2);
}, pageable);
System.out.println("数据=" + page.getContent());
System.out.println("总页数=" + page.getTotalPages());
System.out.println("总行数=" + page.getTotalElements());
}
/**
* specification分页查询
*/
@Test
public void testSpecification3() {
List<Order> list = orderDao.findAll((root, query, builder) -> {
Join<Order, Customer> join = root.join("customer", JoinType.INNER);
return builder.equal(join.get("custName"), "张三三");
});
for (Order order : list) {
System.out.println(order.getProductName());
}
}
}