Spring Data是Spring下的子项目,大大简化了Dao层的开发量,最近终于把这个撸完,简单做一下记录,防止这该死的脑袋又忘记。
一、关于传统数据库的操作–JDBC的梳理
1.首先创建获取和销毁Connection对象的工具类
JDBCUtile工具类
package com.hhu.util;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* jdbc的工具类,用于Connection的获取和资源的销毁
*/
public class JDBCUtil {
/**
* 将方法定义成静态方法,这样可以直接使用“类名+方法名”的方式方便调用
* @return 获取的驱动
* @throws Exception
*/
public static Connection getConnection() throws Exception {
//读取jdbc的配置文件
InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties properties = new Properties();
//将输入流载入properties
properties.load(is);
String userName = properties.getProperty("jdbc.userName");
String password = properties.getProperty("jdbc.password");
String url = properties.getProperty("jdbc.url");
String driverClass = properties.getProperty("jdbc.driverClass");
//加载驱动
Class.forName(driverClass);
Connection conn = DriverManager.getConnection(url, userName, password);
return conn;
}
/**
* 关闭连接资源
* @param rs 结果集
* @param st 编译对象
* @param conn 连接对象
*/
public static void closeResource(ResultSet rs, Statement st, Connection conn) {
if(rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(st!=null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
2.操作数据库
package com.hhu.jdbc;
import com.hhu.dao.Student;
import com.hhu.util.JDBCUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
/**
* 利用jdbc对数据库进行增删改查
*/
public class StudentDao {
/**
* 增操作
*/
public void insertStudent(Student s) {
Connection conn = null;
PreparedStatement pst = null;
ResultSet rs = null;
String sql = "insert into student(name, age) values(?,?)";
try {
conn = JDBCUtil.getConnection();
//预编译sql语句
pst = conn.prepareStatement(sql);
//给占位符设参
pst.setString(1, s.getName());
pst.setInt(2, s.getAge());
//执行SQL
pst.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.closeResource(rs, pst, conn);
}
}
/**
* 删操作
*/
public void deleteById(int id) {
Connection conn = null;
PreparedStatement pst = null;
ResultSet rs = null;
String sql = "delete from student where id=?";
try {
conn = JDBCUtil.getConnection();
//预编译sql语句
pst = conn.prepareStatement(sql);
//给占位符设参
pst.setInt(1, id);
//执行SQL
pst.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.closeResource(rs, pst, conn);
}
}
/**
* 该操作
*/
public void updateById(String name, int age, int id) {
Connection conn = null;
PreparedStatement pst = null;
ResultSet rs = null;
String sql = "update student set name=?,age=? where id=?";
try {
conn = JDBCUtil.getConnection();
//预编译sql语句
pst = conn.prepareStatement(sql);
//给占位符设参
pst.setString(1, name);
pst.setInt(2, age);
pst.setInt(3, id);
//执行SQL
pst.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.closeResource(rs, pst, conn);
}
}
/**
* 查操作
*/
public List<Student> findAll() {
Connection conn = null;
PreparedStatement pst = null;
ResultSet rs = null;
String sql = "select id,name,age from student";
List<Student> list = new ArrayList<Student>();
try {
conn = JDBCUtil.getConnection();
System.out.println(conn);
//预编译sql语句
pst = conn.prepareStatement(sql);
//执行SQL
rs = pst.executeQuery(sql);
System.out.println(rs);
while(rs.next()) {
Student s = new Student(rs.getString("name"),rs.getInt("age"));
list.add(s);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.closeResource(rs, pst, conn);
}
return list;
}
}
二、SpringData对数据库的操作
利用SpringData操作是不需要手动建表,这一点和Hibernate相似,这一点注意实体类中的注解
1.依赖的引入
<!--引入Spring-data-jpa的两个依赖:spring-data-jpa和hibernate-entityManager,一定注意两者的版本,
否则会出现entitymanager无法打开的异常-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.8.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.6.Final</version>
</dependency>
2.配置Spring
<?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: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/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="username" value="root"></property>
<property name="password" value="root"></property>
<property name="url" value="jdbc:mysql://localhost:3306/spring_date"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>
<!--配置HibernateEntityManagerFactory-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean>
</property>
<property name="packagesToScan" value="com.hhu"></property>
<!--jpa的配置-->
<property name="jpaProperties">
<props>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<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>
<!--配置支持注解的事务-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
<!-- 配置spring data能够扫描出来的包 -->
<jpa:repositories base-package="com.hhu" entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>
<!--可以直接用context的全局扫描了,如果配置context就不需要配置上述的jpa的扫描-->
<context:component-scan base-package="com.hhu"></context:component-scan>
</beans>
3.创建实体类
package com.hhu.dao;
import javax.persistence.*;
/**
* 雇员,这个实体类用于测试jpa对于table的创建
* jpa中所有的基本数据类型建议使用封装类型
*/
@Entity//这个注解表明他是一个实体类,根据xml中的配置会自动创建这个实体类的映射表
//@Table(name = "")//给table命名,默认就是实体名的小写
public class Employee {
@Id//这个注解表明这个属性值是id
@GeneratedValue//这个注解表明他是策略是id自增
private Integer id;
@Column(length = 20)//该注解是指定创建表字段时候的长度(默认为255)
private String name;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Employee(String name, Integer age) {
this.name = name;
this.age = age;
}
public Employee() {
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
4.数据库操作类–Repository
Repository是jpa包下的核心类,也是数据库操作类, Repository是空接口不提供任何方法,是个标记接口,和Serializable和Cloneable一样,但是不一样的是,继承这个接口会自动被Spring管理!!不需要手动加注解。Repository体系中主要包括以下四类子接口:1.内置CrudRepository接口(即内部帮我们写好了save,update,delete方法),2.PagingAndSortingRepository(分页和排序) ,3.JpaRepository接口,4.JpaSpecificationExecutor接口。可以根据自己的需求选择其中的一个或者多个接口。
在贴代码之前,简单说一下Jpa的命名规则:千万不能乱写,jpa有自己的规则。
* jap的基本命名规则:
* 1.And/Or
* 即按多个条件进行查询,比如这里按照姓名和年龄去查询,那么方法名必须写成findByNameAndAge()
* Or同理
*
* 2.Between/LessThan/GreaterThan
* 查询分范围内的数据,必须带上范围字段,比如查询一定范围内的年龄,方法名必须为findByAgeBetween()
*LessThan(小于)和GreaterThan(大于)同上
*
* 3.Like/NotLike
* 即模糊匹配,必须带上匹配的字段,比如按名字模糊匹配(?ak),那么方法名为findByNameLike()
* NotLike同理
* 等等。。。
*
* 4.StartingWith/EndingWith/Containing(较为常用)
* 这三个是上诉第三点的具体版本,写法一样,它们模糊查询匹配如下:
* 比如查询行年
*
* 5.OrderBy
* 必须指明按哪个字段的何种方式排序,必须按年龄降序排列
* 比如先按姓名查找然后按年龄降序
* findByNameOrderByAgeDesc
1.Repositoy接口
一般情况下,就是以往的Dao层,这里正常定义成接口然后让它实现Repository接口,就可以进行一些简单的数据库的操作,如下:
package com.hhu.repository;
import com.hhu.dao.Employee;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.RepositoryDefinition;
import org.springframework.data.repository.query.Param;
import java.util.List;
@RepositoryDefinition(domainClass = Employee.class,idClass = Integer.class)
public interface EmployeeRepository {
/*注意,这里是声明成接口的方式,一般情况下,Repository是jpa包下的核心类,会带有
两个泛型,像这样的形式Repository<T , ID>,其中T表明此Repository需要操作的对象,
这个实例里面是对Employee的操作,而Employee实体类的主键为id是Integer类型,所以这
里应该写成Repository<Employee, Integer>,前面定义id为Integer不定义成int,也只考
虑到泛型这一点,这里一定要带上泛型,否则会报错,默认将id当成varchar类型但他是Integer!!
Repository是空接口不提供任何方法,是个标记接口,和Serializable和Cloneable一样,但是不
一样的是,继承这个接口会自动被Spring管理!!
只要继承这个接口(送一个面试题,接口之间的继承使用的是extends关键字而不是implements
关键字),那么那都不需要写实现类,当然除了继承这个接口,还可以不用继承的方式可以使用
RepositoryDefintion这个注解的方式来代替,如下的方式:
@RepositoryDefinition(domainClass = Employee.class,idClass = Integer.class)
*/
/**
* 自动查询的关键,千万不能乱写,jpa有自己的规则,这里如果写成test()那么是无法自动匹配查询的!!
*
* Repository的主要结构体系:
* 1.内置CrudRepository接口(即内部帮我们写好了save,update,delete方法)
* 具体的方法如下:
* save(entity) findOne(id) finaAll() delete(entity) deleteAll()
* save(entities) exists(id) delete(id) delete(entities)
*
*
* 2.PagingAndSortingRepository(分页和排序)
* 这个接口包含了分页和排序的功能,
* 2.1带排序功能的查询
* findAll(Sort sort)
*
* 2.2带排序的分页查询
* findAll(Pageable pageable)
*
* 3.JpaRepository接口
* 这个接口中主要有如下的一些方法:
* findAll() findAll(Sort sort) save(entities) flush() deleteInBatch(entities)
*
*
* 4.JpaSpecificationExecutor接口
* 这个接口封装了JPA Criteria的查询条件
*
*
* jap的基本命名规则:
* 1.And/Or
* 即按多个条件进行查询,比如这里按照姓名和年龄去查询,那么方法名必须写成findByNameAndAge()
* Or同理
*
* 2.Between/LessThan/GreaterThan
* 查询分范围内的数据,必须带上范围字段,比如查询一定范围内的年龄,方法名必须为findByAgeBetween()
*LessThan(小于)和GreaterThan(大于)同上
*
* 3.Like/NotLike
* 即模糊匹配,必须带上匹配的字段,比如按名字模糊匹配(?ak),那么方法名为findByNameLike()
* NotLike同理
* 等等。。。
*
* 4.StartingWith/EndingWith/Containing(较为常用)
* 这三个是上诉第三点的具体版本,写法一样,它们模糊查询匹配如下:
* 比如查询行年
*
* 5.OrderBy
* 必须指明按哪个字段的何种方式排序,必须按年龄降序排列
* 比如先按姓名查找然后按年龄降序
* findByNameOrderByAgeDesc
*
*
* 当然按照上述的规则定义方法名可能名字会非常长,另外一个是对于复杂的查询难以实现,
* 这个时候可以利用@Query这个注解进行自定义书写SQL,而且使用这个注解的时候就可以
* 丢弃上述的一套命名规则了,因为SQL语句此时是自己写的
*
*
*
* @param name
* @return
*/
public Employee findByName(String name);
/**
* 查询name模糊匹配并且age小于限定值
*/
public List<Employee> findByNameStartingWithAndAgeLessThan(String name,Integer age);
public List<Employee> findByNameEndingWithAndAgeGreaterThan(String name, Integer age);
public List<Employee> findByNameContaining(String name);
public List<Employee> findByNameLike(String name);
/**
* 查询名字在某一范围内(关键字In)或者年龄小于某一限定值,
* 所以名字的方查询范围传入List集合
*/
public List<Employee> findByNameInOrAgeLessThan(List<String> names, Integer age);
/**
* 获取id最大员工的信息
*
* @return
*/
//注意:这里的不是写表名而是写类名
@Query("select e from Employee e where id=(select max(id) from Employee e2)")//这个注解中直接写SQL语句即可
public Employee getMaxId();
//方式1:利用注解传入参数查询满足条件的记录,占位符的方式,即索引参数
@Query("select e from Employee e where e.name=?1 and e.age=?2")
public List<Employee> getTestRecords(String name,Integer age);
//方式2:按照命名参数的方式来写SQL,只是将占位符换做了“:参数名”的方式,在形参上加上@Param的注解即可
@Query("select e from Employee e where e.name=:name and e.age=:age")
public List<Employee> getTestRecords2(@Param("name") String name, @Param("age")Integer id);
//方式1:Like关键字,有点类似于containing了,用占位符,即索引参数
@Query("select e from Employee e where e.name like %?1%")
public List<Employee> queryLike1(String name);
//方式2:Like关键字同样可以使用命名参数的方式
@Query("select e from Employee e where e.name like %:name%")
public List<Employee> queryLike2(@Param("name") String name);
//打开原生的方式进行查询,一定要把nativeQuery设置为true,此时就可以用表名去查询
@Query(nativeQuery = true, value = "select count(id) from employee")
public long getCount();
//写操作必须加Transactional和Modifying注解,只是事务注解一般是放在Service层的
//@Transactional
@Modifying//允许修改的意思
@Query("update Employee e set e.age=:age where e.id=:id")
public void update(@Param("age") Integer age, @Param("id") Integer id);
}
2.CrudRepository接口
package com.hhu.repository;
import com.hhu.dao.Employee;
import org.springframework.data.repository.CrudRepository;
/**
* 继承CrudRepository接口,该接口又继承了顶级接口Repository
*/
public interface EmployeeCrudRepository extends CrudRepository<Employee, Integer>{
}
3.PagingAndSortingRepository接口
package com.hhu.repository;
import com.hhu.dao.Employee;
import org.springframework.data.repository.PagingAndSortingRepository;
/**
* 继承分页查询的接口PagingAndSortingRepository
*/
public interface EmployeePagingAndSortingRepository extends PagingAndSortingRepository<Employee, Integer>{
}
4.JpaRepository接口
package com.hhu.repository;
import com.hhu.dao.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* 测试JpsRepository接口
*/
public interface EmployeeJpaRepository extends JpaRepository<Employee, Integer>{
}
5.JpaSpecificationExecutor接口
package com.hhu.repository;
import com.hhu.dao.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface EmployeeJpaSpecificationExecutor extends JpaRepository<Employee, Integer>, JpaSpecificationExecutor<Employee> {
}
最后是测试代码,注意后面几种接口的调用方法
package com.hhu.repository;
import com.hhu.dao.Employee;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.List;
/**
* 测试Repository
*/
public class EmployeeRepositoryTest {
//定义上下文
private ApplicationContext ctx = null;
private EmployeeRepository employeeRepository = null;
//分页接口
private EmployeePagingAndSortingRepository employeePagingAndSortingRepository = null;
//jpa接口
private EmployeeJpaRepository employeeJpaRepository = null;
//jpaSpecificationExecutor接口
private EmployeeJpaSpecificationExecutor employeeJpaSpecificationExecutor = null;
@Before
public void doBefore() {
System.out.println("set up...");
ctx = new ClassPathXmlApplicationContext("beans.xml");
employeeRepository = (EmployeeRepository) ctx.getBean(EmployeeRepository.class);
employeePagingAndSortingRepository = (EmployeePagingAndSortingRepository)ctx.getBean("employeePagingAndSortingRepository");
employeeJpaRepository = (EmployeeJpaRepository)ctx.getBean("employeeJpaRepository");
employeeJpaSpecificationExecutor = (EmployeeJpaSpecificationExecutor)ctx.getBean("employeeJpaSpecificationExecutor");
}
@Test
public void findByNameStartWithAndAgeLessThanTest() {
List<Employee> list = employeeRepository.findByNameStartingWithAndAgeLessThan("test",24);
System.out.println(list);
}
@Test
public void findByNameEndingWithAndAgeGreaterLanTest() {
List<Employee> list = employeeRepository.findByNameEndingWithAndAgeGreaterThan("5",23);
System.out.println(list);
}
@Test
public void employeeRepositoryTest() {
String name = "jack";
Employee employee = employeeRepository.findByName(name);
System.out.println(employee);
}
@Test
public void findByNameContainingTest() {
List<Employee> list = employeeRepository.findByNameContaining("5");
System.out.println(list);
}
@Test
public void findByNameLike() {
List<Employee> list = employeeRepository.findByNameLike("5");
System.out.println(list);
}
@Test
public void findByNameInOrAgeLessThan() {
List<String> names = new ArrayList<String>();
names.add("jack");
names.add("air");
names.add("test");
names.add("test1");
List<Employee> list = employeeRepository.findByNameInOrAgeLessThan(names,23);
System.out.println(list);
}
@Test
public void getMaxIdTest() {
Employee e = employeeRepository.getMaxId();
System.out.println(e);
}
@Test
public void getTestRecodsTest() {
List<Employee> e = employeeRepository.getTestRecords("test5",27);
System.out.println("select e:" + e);
}
@Test
public void getTestRecords2Test() {
List<Employee> list = employeeRepository.getTestRecords2("jack",25);
System.out.println(list);
}
@Test
public void queryLike1Test() {
List<Employee> list = employeeRepository.queryLike1("test");
System.out.println(list);
}
@Test
public void queryLike2Test() {
List<Employee> list = employeeRepository.queryLike2("a");
System.out.println(list);
}
@Test
public void getCountTest() {
System.out.println(employeeRepository.getCount());
}
@Test
public void update() {
employeeRepository.update(18,11);
}
/*
测试分页
*/
@Test
public void pageTest() {
//Page对象是Spring内置的对象,从第0页开始,每页显示5条记录
Pageable page = new PageRequest(1, 5);//创建一个Page对象,第1页(即第二页),每页显示5条记录
Page<Employee> employeePage = employeePagingAndSortingRepository.findAll(page);
System.out.println("总页数:" + employeePage.getTotalPages());
System.out.println("总记录数:" + employeePage.getTotalElements());
System.out.println("当前页码(从第0页开始):" + employeePage.getNumber());
System.out.println("当前页记录的集合:" + employeePage.getContent());
System.out.println("当前页面包含的记录数:" + employeePage.getNumberOfElements());
}
@Test
public void PageSortTest() {
//创建排序对象(排序方式,按照那个字段排序),注意这里是先排序再分页
Sort.Order order = new Sort.Order(Sort.Direction.DESC, "id");
Sort sort = new Sort(order);
Pageable page = new PageRequest(0, 8, sort);
Page<Employee> sortPage = employeePagingAndSortingRepository.findAll(page);
System.out.println("当前页的记录数:" + sortPage.getNumberOfElements());
System.out.println("当前页码:" + sortPage.getNumber());
System.out.println("当前页记录的集合:" + sortPage.getContent());
System.out.println("总记录数:" + sortPage.getTotalElements());
System.out.println("总页数:" + sortPage.getTotalPages());
}
/**
* 测试JpaRepository接口
*/
@Test
public void JpaTest() {
Employee e = employeeJpaRepository.findOne(99);
System.out.println(e);
boolean r1 = employeeJpaRepository.exists(78);
boolean r2 = employeeJpaRepository.exists(120);
System.out.println("r1:" + r1);
System.out.println("r2:" + r2);
}
/**
* 测试JpaSpecificationExecutor接口
*
* 实现功能:分页(第一页,每页5条记录)+排序(按id降序)+查询条件(比如年龄大于50)
*/
@Test
public void jpaSpecificationTest() {
Sort.Order order = new Sort.Order(Sort.Direction.DESC, "id");
Sort sort = new Sort(order);
Pageable pageable = new PageRequest(0, 5, sort);
//创建Specification对象
Specification<Employee> specification = new Specification<Employee>() {
/***
*
* @param root 就是待查询的数据类型(这里就是Employee)
* @param criteriaQuery 添加查询条件
* @param criteriaBuilder 构建predicate返回
* @return
*/
@Override
public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//root就是查询的对象Employee,从里面可以获取Employee中的age属性
Path path = root.get("age");
//criteriaBuilder就是构建的查询条件
Predicate predicate = criteriaBuilder.gt(path, 50);
return predicate;
}
};
//这里可以将查询的条件添加进finadAll()方法中
Page<Employee> page = employeeJpaSpecificationExecutor.findAll(specification, pageable);
System.out.println("总页数:" + page.getTotalPages());
System.out.println("总记录数:" + page.getTotalElements());
System.out.println("当前页记录的集合:" + page.getContent());
System.out.println("当前页的记录数:" + page.getNumberOfElements());
System.out.println("当前页码:" + page.getNumber());
}
@After
public void doAfter() {
if(ctx!=null) {
ctx = null;
}
}
}
【注意】最后需要提醒的是关于JPA里面的读操作和写操作的区别(利用@Query注解时写操作一定要加@Modifying注解允许修改,另外也必须加事务注解@Transactional(这个一般是加在Service层))。比如下面的Service层
package com.hhu.service;
import com.hhu.dao.Employee;
import com.hhu.repository.EmployeeCrudRepository;
import com.hhu.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.List;
@Service
public class EmployeeService {
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private EmployeeCrudRepository employeeCrudRepository;
@Transactional
public void update(Integer age, Integer id) {
employeeRepository.update(age, id);
}
@Transactional
public void save(List<Employee> list) {
employeeCrudRepository.save(list);
}
}
完整代码见:https://github.com/Jacksonary/CodeRepository/tree/master/SpringData