SpringData可以结合JPA使用也可以结合JDBC使用
新建一个maven工程
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.springdata.jpagroupId>
<artifactId>springdata_jpaartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.0.5.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>5.0.5.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>5.0.5.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>5.0.5.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.0.5.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>5.0.5.RELEASEversion>
dependency>
<dependency>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-coreartifactId>
<version>5.3.3.Finalversion>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-entitymanagerartifactId>
<version>5.3.3.Finalversion>
dependency>
<dependency>
<groupId>org.hibernate.commongroupId>
<artifactId>hibernate-commons-annotationsartifactId>
<version>5.0.1.Finalversion>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.11version>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>c3p0artifactId>
<version>0.9.5.2version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-jpaartifactId>
<version>2.1.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-commonsartifactId>
<version>2.1.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.8.0-beta2version>
dependency>
dependencies>
project>
jdbc.user=root
jdbc.password=mysql123
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///jpa?characterEncoding=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:tx="http://www.springframework.org/schema/tx"
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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<context:component-scan base-package="com.springdata.jpa">context:component-scan>
<context:property-placeholder location="classpath:db.properties">context:property-placeholder>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}">property>
<property name="password" value="${jdbc.password}">property>
<property name="driverClass" value="${jdbc.driverClass}">property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}">property>
bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource">property>
<property name="packagesToScan" value="com.springdata.jpa">property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">bean>
property>
<property name="jpaProperties">
<props>
<prop key="hibernate.show_sql">trueprop>
<prop key="hibernate.format_sql">trueprop>
<prop key="hibernate.hbm2ddl.auto">updateprop>
props>
property>
bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory">property>
bean>
<tx:annotation-driven transaction-manager="transactionManager">tx:annotation-driven>
<jpa:repositories base-package="com.springdata.jpa"
entity-manager-factory-ref="entityManagerFactory">jpa:repositories>
beans>
如果报错:EntityPathResolver must not be null!
要配置 包扫描,使扫描到repository
package com.springdata.jpa.entities;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table(name = "tb_cat")
public class Cat implements Serializable {
@Id
@GeneratedValue
private Integer id;
@Column(name = "cat_name")
private String catName;
@Column(name = "date")
@Temporal(TemporalType.DATE)
private Date date;
// 省略了getter/setter和toString
}
// 不需要手动配置加载到Spring容器中去
// 继承Repository,第一个参数是对应的实体类,第二个参数是对应的主键类型
public interface CatRepository extends Repository<Cat, Integer> {
// getBy后sin 可以接对象的属性
Cat getByCatName(String name);
}
注:测试前,在数据库中手动添加一条数据。
@Test
public void testHelloWorld() {
ApplicationContext act = new ClassPathXmlApplicationContext("application.xml");
CatRepository bean = act.getBean(CatRepository.class);
Cat aa = bean.getByCatName("aa");
System.out.println(aa);
}
控制台打印:
Hibernate:
select
cat0_.id as id1_0_,
cat0_.cat_name as cat_name2_0_,
cat0_.date as date3_0_
from
tb_cat cat0_
where
cat0_.cat_name=?
Cat{id=1, catName='aa', date=2018-10-03}
// 第一个参数是实体对象类,第二个参数是对象的主键类型
public interface DogDao extends Repository<Dog, Integer>{
Dog getByDogName(String dogName);
}
// 第一个属性domainClass的值是实体类对象类,第二个属性的对象的主键类型
@RepositoryDefinition(domainClass = Dog.class, idClass = Integer.class)
public interface DogDao {
Dog getByDogName(String dogName);
}
1.查询方法要以get,find,read开头
2.方法名的定义要依据规范
3.查询条件可以用And或Or连接
3.查询字段用对象实体类属性名代替
4.具体命名规则如下:
Keyword | Sample | JPQL snippet |
---|---|---|
And |
findByLastnameAndFirstname |
… where x.lastname = ?1 and x.firstname = ?2 |
Or |
findByLastnameOrFirstname |
… where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals |
findByFirstname ,findByFirstnameIs ,findByFirstnameEquals |
… where x.firstname = ?1 |
Between |
findByStartDateBetween |
… where x.startDate between ?1 and ?2 |
LessThan |
findByAgeLessThan |
… where x.age < ?1 |
LessThanEqual |
findByAgeLessThanEqual |
… where x.age <= ?1 |
GreaterThan |
findByAgeGreaterThan |
… where x.age > ?1 |
GreaterThanEqual |
findByAgeGreaterThanEqual |
… where x.age >= ?1 |
After |
findByStartDateAfter |
… where x.startDate > ?1 |
Before |
findByStartDateBefore |
… where x.startDate < ?1 |
IsNull |
findByAgeIsNull |
… where x.age is null |
IsNotNull,NotNull |
findByAge(Is)NotNull |
… where x.age not null |
Like |
findByFirstnameLike |
… where x.firstname like ?1 |
NotLike |
findByFirstnameNotLike |
… where x.firstname not like ?1 |
StartingWith |
findByFirstnameStartingWith |
… where x.firstname like ?1 (parameter bound with appended % ) |
EndingWith |
findByFirstnameEndingWith |
… where x.firstname like ?1 (parameter bound with prepended % ) |
Containing |
findByFirstnameContaining |
… where x.firstname like ?1 (parameter bound wrapped in % ) |
OrderBy |
findByAgeOrderByLastnameDesc |
… where x.age = ?1 order by x.lastname desc |
Not |
findByLastnameNot |
… where x.lastname <> ?1 |
In |
findByAgeIn(Collection |
… where x.age in ?1 |
NotIn |
findByAgeNotIn(Collection |
… where x.age not in ?1 |
True |
findByActiveTrue() |
… where x.active = true |
False |
findByActiveFalse() |
… where x.active = false |
IgnoreCase |
findByFirstnameIgnoreCase |
… where UPPER(x.firstame) = UPPER(?1) |
@RepositoryDefinition(domainClass = Dog.class, idClass = Integer.class)
public interface DogDao {
Dog getByDogName(String dogName);
List<Dog> getByDogNameLikeAndIdLessThan(String like, Integer id);
List<Dog> findByDogNameStartingWithAndIdGreaterThan(String start, Integer id);
List<Dog> readByDogNameLikeOrId(String name, Integer id);
}
@RepositoryDefinition(domainClass = Dog.class, idClass = Integer.class)
public interface DogDao {
Dog getByDogName(String dogName);
List<Dog> getByDogNameLikeAndIdLessThan(String like, Integer id);
List<Dog> findByDogNameStartingWithAndIdGreaterThan(String start, Integer id);
List<Dog> readByDogNameLikeOrId(String name, Integer id);
// 使用@Query注解可以自定义jpql语句
@Query("SELECT d1 FROM Dog d1 WHERE d1.id =(SELECT MAX(d2.id) FROM Dog d2)")
Dog selectDogByMaxId(); // 方法命名可以不用spring data jpa提供的命名规范了
}
@RepositoryDefinition(domainClass = Dog.class, idClass = Integer.class)
public interface DogDao {
// 使用@Query注解可以自定义jpql语句
@Query("SELECT d1 FROM Dog d1 WHERE d1.id =(SELECT MAX(d2.id) FROM Dog d2)")
Dog selectDogByMaxId();
// 写占位符?的时候,一定要指定数字,这个数字代表这个占位符接收的是方法中对应的第几个参数
@Query("SELECT d FROM Dog d WHERE d.id = ?2 and d.dogName = ?1")
List<Dog> selectDogByDogNameAndId(String dogName, Integer id);
}
@RepositoryDefinition(domainClass = Dog.class, idClass = Integer.class)
public interface DogDao {
// 使用@Query注解可以自定义jpql语句
@Query("SELECT d1 FROM Dog d1 WHERE d1.id =(SELECT MAX(d2.id) FROM Dog d2)")
Dog selectDogByMaxId();
@Query("SELECT d FROM Dog d WHERE d.id = ?2 and d.dogName = ?1")
List<Dog> selectDogByDogNameAndId(String dogName, Integer id);
// 使用 :参数名的方式,指定要接收的参数的命名,在方法的参数列表位置通过@Param参数指定对应的参数的命名,
// 当两个参数命名一致时,才能写入值
@Query("SELECT d FROM Dog d WHERE d.id = :id and d.dogName = :dogName")
List<Dog> selectDogsByNameAndId(@Param("dogName") String name, @Param("id")Integer id);
}
方式一:
// 这个方法进行模糊查询的时候,要传入%号
@Query("FROM Dog d WHERE d.dogName like ?1")
public List<Dog> getDogByNameLike(String like);
// 方法的使用,传入的参数要带上%
List<Dog> dogs = dao.getDogByNameLike("%a%");
方式二:
// 这里%也可以写在参数位置
@Query("FROM Dog d WHERE d.dogName like %:name")
public List<Dog> getDogsByNameLike(@Param("name") String dogName);
// 方法的使用,参数位置可以不传入%
List<Dog> dogs = dao.getDogsByNameLike("a");
// 在@Query注解中设置nativeQuery属性为true
@Query(value = "SELECT COUNT(1) FROM tb_dog", nativeQuery = true)
Integer getCount();
// 参数可以写成占位符的形式,方法中传参,依据占位符的顺序
@Query(value = "select * from tb_dog where id = ? and dog_name = ?", nativeQuery = true)
Dog getDogById(Integer id, String name);
修改:
@RepositoryDefinition(domainClass = Person.class, idClass = Integer.class)
public interface PersonDao {
@Query("FROM Person p WHERE p.id = ?1")
Person getPersonById(Integer id);
@Query(value = "SELECT * FROM tb_person WHERE last_name = ?", nativeQuery = true)
Person getPersonByLastName(String lastName);
// 使用修改和删除时,使用@Modifying+@Query注解
@Modifying
@Query("UPDATE Person p SET p.lastName = :lastName WHERE p.id = :id")
int updateLastNameById(@Param("lastName")String lastName, @Param("id")Integer id);
}
如果直接调用这个Repository中的方法会报错!
org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query
修改和删除操作时,必须要有事务!
所以修改代码,新建一个PersonService类,在PersonService中使用PersonDao方法,并添加事务!
@Service // 加入到Spring容器中,注意配置包扫描
public class PersonService {
private PersonDao personDao;
// 在构造器位置,personDao可以自动注入,类似于@Autowired
public PersonService(PersonDao personDao) {
this.personDao = personDao;
}
@Transactional // 添加事务支持
public void updatePerson(String lastName, Integer id) {
int i = personDao.updateLastNameById(lastName, id);
System.out.println(i);
}
}
测试:
@Test
public void testUpdate() {
PersonService personService = act.getBean(PersonService.class);
personService.updatePerson("小明", 2);
}
删除:
@RepositoryDefinition(domainClass = Person.class, idClass = Integer.class)
public interface PersonDao {
@Query("FROM Person p WHERE p.id = ?1")
Person getPersonById(Integer id);
@Query(value = "SELECT * FROM tb_person WHERE last_name = ?", nativeQuery = true)
Person getPersonByLastName(String lastName);
@Modifying
@Query("UPDATE Person p SET p.lastName = :lastName WHERE p.id = :id")
int updateLastNameById(@Param("lastName")String lastName, @Param("id")Integer id);
// 使用@Modifying和@Query注解完成删除操作
@Modifying
@Query(value = "DELETE FROM tb_person WHERE id = ?", nativeQuery = true)
int deleteById(Integer id);
}
service中使用添加事务支持:
@Service // 加入到Spring容器中,注意配置包扫描
public class PersonService {
private PersonDao personDao;
// 在构造器位置,personDao可以自动注入,类似于@Autowired
public PersonService(PersonDao personDao) {
this.personDao = personDao;
}
@Transactional // 添加事务支持
public void updatePerson(String lastName, Integer id) {
int i = personDao.updateLastNameById(lastName, id);
System.out.println(i);
}
@Transactional // 添加事务支持
public void deletePerson(Integer id) {
int i = personDao.deleteById(id);
System.out.println(i);
}
}
测试:
@Test
public void testDelete() {
PersonService personService = act.getBean(PersonService.class);
personService.deletePerson(1);
}
CrudRepository接口中定义了一些能用的增删改查方法
// 继承CrudRepository
public interface PersonRepository extends CrudRepository<Person, Integer>{
}
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
<S extends T> S save(S entity); //保存单个对象方法
<S extends T> Iterable<S> saveAll(Iterable<S> entities); //批量保存方法
Optional<T> findById(ID id); // 查找方法
boolean existsById(ID id); // 判断是否存在
Iterable<T> findAll(); // 查找所有
Iterable<T> findAllById(Iterable<ID> ids); // 通过id查找所有
long count(); // 获取数据条数
void deleteById(ID id); // 通过id删除
void delete(T entity); // 通过实体对象删除
void deleteAll(Iterable<? ext ends T> entities); // 批量删除
void deleteAll(); // 删除所有
}
测试:
@Test
public void findAllById() {
PersonRepository personRepository = act.getBean(PersonRepository.class);
// findAllById()
Iterable<Person> res = personRepository.findAllById(Arrays.asList(1,2,3,4,5));
System.out.println(res);
}
// 继承可实现分页和排序
public interface PersonPagingAndSortingRepository extends PagingAndSortingRepository<Person, Integer> {
}
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
// 排序
Iterable<T> findAll(Sort sort);
// 分页
Page<T> findAll(Pageable pageable);
}
使用方法:
分页:
@Test
public void testPageAndSort() {
PersonPagingAndSortingRepository dao = act.getBean(PersonPagingAndSortingRepository.class);
PageRequest pageable = new PageRequest(0, 2);
Page<Person> page = dao.findAll(pageable);
System.out.println(page.getNumber()); // 当前页 页码从0开始计算的
System.out.println(page.getNumberOfElements()); // 总页数
System.out.println(page.getSize()); // 每页大小
System.out.println(page.getContent()); // 每页内容
}
// 接口继承JpaRepository
public interface CustomerDao extends JpaRepository<Customer, Integer> {
}
// JpaRepository是PagingAndSortingRepository,
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
List<T> findAll();
List<T> findAll(Sort sort);
List<T> findAllById(Iterable<ID> ids);
<S extends T> List<S> saveAll(Iterable<S> entities);
void flush();
<S extends T> S saveAndFlush(S entity);
void deleteInBatch(Iterable<T> entities);
void deleteAllInBatch();
T getOne(ID id);
@Override
<S extends T> List<S> findAll(Example<S> example);
@Override
<S extends T> List<S> findAll(Example<S> example, Sort sort);
}
测试:
@Test
public void test() {
Customer customer = new Customer();
customer.setLastName("小芳");
customer.setBirthDay(new Date());
customer.setId(1);
// saveAndFlush()方法,存在就更新,不存在就插入
customerDao.saveAndFlush(customer);
}
public interface CustomerDao extends JpaRepository<Customer, Integer>, JpaSpecificationExecutor<Customer> {
}
使用:
@Test
public void test02() {
Specification<Customer> specification = new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
// 构造比较查询条件
Path path = root.get("id");
Predicate predicate = criteriaBuilder.gt(path, 0);
return predicate;
}
};
List<Customer> all = customerDao.findAll(specification);
System.out.println(all);
}
@Test
public void test02() {
Specification<Customer> specification = new Specification<Customer>() {
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
Path<String> lastName = root.get("lastName");
Predicate predicate = criteriaBuilder.like(lastName, "%小");
Path<Integer> id = root.get("id");
Predicate predicate1 = criteriaBuilder.equal(id, 2);
// 两个条件and连接
query.where(predicate, predicate1);
return null;
}
};
List<Customer> all = customerDao.findAll(specification);
System.out.println(all);
}
public interface CustomerDao extends JpaRepository<Customer, Integer>,
JpaSpecificationExecutor<Customer> {
}
public interface CustomerRepository {
// 自已在接口中定义的方法
public void test();
}
// 继承自定义接口
public class CustomerDaoImpl implements CustomerRepository {
// 可以使用EntityManager
@PersistenceContext
private EntityManager entityManager;
// 实现方法
public void test() {
Customer customer = entityManager.find(Customer.class, 2);
System.out.println(customer);
}
}
public interface CustomerDao extends JpaRepository<Customer, Integer>,
JpaSpecificationExecutor<Customer>,
//继承自定义接口
CustomerRepository {
}
测试:
@Test
public void repository() {
customerDao.test();
}