Spring Data’s mission is to provide a familiar and consistent, Spring-based programming model for data access while still retaining the special traits of the underlying data store.
常用子项目
import java.sql.*;
public class JdbcUtil {
public static Connection getConnection() throws Exception {
String url = "jdbc:mysql://localhost/db_springboot?useSSL=false";
String user = "root";
String password = "123456";
String driverClass = "com.mysql.jdbc.Driver";
Class.forName(driverClass);
return DriverManager.getConnection(url, user, password);
}
public static void release(ResultSet resultSet, Statement statement,Connection connection) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
import java.util.List;
public interface UserDAO {
List<User> query();
}
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class UserDAOImpl implements UserDAO {
@Override
public List<User> query() {
List<User> users = new ArrayList<>();
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
String sql = "select * from user";
try {
connection = JdbcUtil.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
User user = null;
while (resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
user = new User();
user.setId(id);
user.setName(name);
user.setAge(age);
users.add(user);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.release(resultSet, statement, connection);
}
return users;
}
}
import org.junit.Assert;
import org.junit.Test;
public class JdbcUtilTest {
@Test
public void getConnection() throws Exception {
Assert.assertNotNull(JdbcUtil.getConnection());
}
}
spring:
datasource:
url: jdbc:mysql://localhost/db_springboot?useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
import org.springframework.jdbc.core.JdbcTemplate;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
@Repository
public class UserDAOImpl implements UserDAO {
private final JdbcTemplate jdbcTemplate;
public UserDAOImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public List<User> query() {
final List<User> users = new ArrayList<>();
String sql = "select * from user";
jdbcTemplate.query(sql, (ResultSet rs) -> {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
User user = new User();
user.setId(id);
user.setName(name);
user.setAge(age);
users.add(user);
});
return users;
}
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class UserDAOImplTest {
@Autowired
private UserDAO userDAO;
@Test
public void query() {
List<User> users = userDAO.query();
users.forEach(System.out::println);
}
}
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Getter
@Setter
@ToString
@Entity
public class User {
@Id
@GeneratedValue
private Integer id;
@Column(length = 10)
@NotEmpty
private String name;
@NotNull
private Integer age;
}
import org.springframework.data.repository.Repository;
public interface UserRepository extends Repository<User, Integer> {
User findByName(String name);
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@Test
public void findByName() {
System.out.println(userRepository.getfindName("LeifChen"));
}
}
public interface Repository {}
Repository 接口是 Spring Data 的核心接口,不提供任何实现方法。是一个空接口,也称为标记接口。
(1) CrudRepository:继承 Repository,实现了 CRUD 相关方法。
S save(S entity);
保存实体 Iterable saveAll(Iterable entities);
保存实体集合Optional findById(ID id);
根据 id 查询实体boolean existsById(ID id);
返回是否存在对应 id 的实体Iterable findAll();
返回所有实体Iterable findAllById(Iterable ids);
根据 ids 查询实体long count();
返回实体数void deleteById(ID id);
根据 id 删除实体void delete(T entity);
根据实体删除void deleteAll(Iterable extends T> entities);
根据实体列表删除void deleteAll();
删除所有实体(2) PagingAndSortingRepository:继承 CurdRepository,实现了分页排序相关方法
Iterable findAll(Sort sort);
查询所有实体并按照 sort 排序Page findAll(Pageable pageable);
分页查询测试代码:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
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.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@Test
public void pageAndSort() {
Pageable pageable = PageRequest.of(0, 5, Sort.Direction.DESC, "age");
Page<User> page = userRepository.findAll(pageable);
System.out.println("查询的总页数:" + page.getTotalPages());
System.out.println("查询的总记录数:" + page.getTotalElements());
System.out.println("查询的当前第几页:" + (page.getNumber() + 1));
System.out.println("查询的当前页面的集合:" + page.getContent());
System.out.println("查询的当前页面的记录数:" + page.getNumberOfElements());
}
}
(3) JpaRepository:继承 PagingAndSortingRepository,实现了 JPA 规范相关方法
测试代码:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@Test
public void find() {
userRepository.findById(3).ifPresent(System.out::println);
}
@Test
public void exist() {
System.out.println("user(3):" + userRepository.existsById(3));
System.out.println("user(100):" + userRepository.existsById(100));
}
}
(4) JpaSpecificationExecutor:用来实现 JPA 的动态复杂条件查询
测试代码:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
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 org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.persistence.criteria.Path;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@SuppressWarnings("unchecked")
@Test
public void complexQuery() {
Pageable pageable = PageRequest.of(0, 5, Sort.Direction.ASC, "age");
Specification<User> specification = (Specification<User>) (root, query, criteriaBuilder) -> {
Path path = root.get("age");
return criteriaBuilder.gt(path, 30);
};
Page<User> page = userRepository.findAll(specification, pageable);
System.out.println("查询的总页数:" + page.getTotalPages());
System.out.println("查询的总记录数:" + page.getTotalElements());
System.out.println("查询的当前第几页:" + (page.getNumber() + 1));
System.out.println("查询的当前页面的集合:" + page.getContent());
System.out.println("查询的当前页面的记录数:" + page.getNumberOfElements());
}
}
自定义 Repository 接口的两种方法:
import com.chen.model.User;
import org.springframework.data.repository.Repository;
public interface UserRepository extends Repository<User, Integer> {
User findByName(String name);
}
import org.springframework.data.repository.RepositoryDefinition;
@RepositoryDefinition(domainClass = User.class, idClass = Integer.class)
public interface UserRepository {
User findByName(String name);
}
参考官方文档
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByNameAndAge | … where x.name = ?1 and x.age = ?2 |
Or | findByNameOrAge | … where x.name = ?1 or x.age = ?2 |
Is,Equals | findByName,findByNameIs,findByNameEquals | … where x.name = ?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 is not null |
Like | findByNameLike | … where x.name like ?1 |
NotLike | findByNameNotLike | … where x.name not like ?1 |
StartingWith | findByNameStartingWith | … where x.name like ?1 (parameter bound with appended %) |
EndingWith | findByNameEndingWith | … where x.name like ?1 (parameter bound with prepended %) |
Containing | findByNameContaining | … where x.name like ?1 (parameter bound wrapped in %) |
OrderBy | findByNameOrderByAgeDesc | … where x.name = ?1 order by x.age desc |
Not | findByNameNot | … 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 | findByNameIgnoreCase | … where UPPER(x.name) = UPPER(?1) |
其中 find 关键字也可以为 get (例如:getByName) ,使用关键字命名方法会导致名称特别长,并且很难实现复杂查询,因此还可以通过注解的方式扩展。
参考代码:
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface UserRepository extends Repository<User, Integer> {
/**
* 根据名称查询用户(使用 JPA 命名规则)
*
* @param name 名称
* @return
*/
User findByName(String name);
/**
* 查询 id 为最大值的用户
*
* @return
*/
@Query("select u from #{#entityName} u where id=(select max(id) from User t1)")
User findByMaxId();
/**
* 根据名称、年龄查询用户(使用 @Query 注解及占位符 ? 绑定参数)
*
* @param name 名称
* @param age 年龄
* @return
*/
@Query("select u from #{#entityName} u where u.name like ?1% and u.age >= ?2")
List<User> findByParam(String name, Integer age);
/**
* 根据名称、年龄查询用户(使用 @Query 注解及 @Param 绑定参数)
*
* @param name 名称
* @param age 年龄
* @return
*/
@Query("select u from #{#entityName} u where u.name like :name% and u.age >= :age")
List<User> findByParam2(@Param("name") String name, @Param("age") Integer age);
/**
* 查询用户数
*
* @return
*/
@Query(nativeQuery = true, value = "select count(1) from user")
long count();
/**
* 根据 id 更新用户年龄
*
* @param id
* @param age 年龄
*/
@Modifying
@Query("update User u set u.age = :age where u.id = :id")
void updateById(@Param("id") Integer id, @Param("age") Integer age);
/**
* 根据 id 删除用户
*
* @param id
*/
@Modifying
@Query("delete from User u where u.id = :id")
void deleteById(@Param("id") Integer id);
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@Test
public void findByName() {
System.out.println(userRepository.findByName("LeifChen"));
}
@Test
public void findByMaxId() {
System.out.println(userRepository.findByMaxId());
}
@Test
public void findByParam() {
System.out.println(userRepository.findByParam("Test", 20));
}
@Test
public void findByParam2() {
System.out.println(userRepository.findByParam2("Test", 20));
}
@Test
public void count() {
System.out.println(userRepository.count());
}
}
import com.chen.repository.UserRepository;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Transactional(rollbackOn = Exception.class)
public void updateById(Integer id, Integer age) {
userRepository.updateById(id, age);
}
@Transactional(rollbackOn = Exception.class)
public void deleteById(Integer id) {
userRepository.deleteById(id);
}
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void updateById() {
userService.updateById(3, 28);
}
@Test
public void deleteById() {
userService.deleteById(3);
}
}