在Spring中使用JdbcTemplate是一种基本的数据访问方式,但是仍然需要较多的代码,为了解决这些大量枯燥的数据操作语句,我们可以使用ORM框架,比如:Hibernate,通过整合Hibernate,解决抽象各个Java实体基本的“增删改查”操作,通常会以泛型的方式封装一个模板Dao来进行抽象简化,那些具体的Dao实现完全就是对模板Dao的简单代理,Spring-data-jpa正可以完成这一项工作。
JPA(Java Persistence API)是Sun官方提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据。他的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate,TopLink,JDO等ORM框架各自为营的局面。Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增删改查等在内的常用实现,并支持扩展,使用 Spring Data JPA 可以极大提高开发效率。
1.新建Spring Boot项目,
2.添加spring jpa依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
----
3.添加User实体类
@Entity public class User { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; @Column(nullable = false) private String name; private Integer age; protected User(){ } public User(String name, int age) { this.name = name; this.age = age; } public Long getId() { return id; } public void setId(Long 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; } }
---
4.添加配置文件
spring.jpa.hibernate.ddl-auto=create spring.datasource.url=jdbc:mysql://localhost:3306/lgtest spring.datasource.username=root spring.datasource.password=pwd spring.datasource.driver-class-name=com.mysql.jdbc.Driver
---spring.jpa.hibernate.ddl-auto值可以是
none
, update
, create
, create-drop,根据Hibernate的说明,他们的意义如下:
none: 表示Hibernate不改变表结构
update: Hibernate会根据Entity修改表结构
create: Hibernate每次加载都创建表,但是SessionFactory关闭时不drop表
create-drop: Hibernate每次加载都创建表,SessionFactory关闭时drop表
所以第一次运行时应该选择Create,之后应该选择为update或none。
内存数据库如H2的默认值为create-drop,MySql默认值为none。
5.创建数据访问接口
public interface UserRepository extends CrudRepository<User, Long> { List<User> findByName(String name); @Modifying @Query("update User u set u.name = ?1 where u.id = ?2") int modifyByIdAndUserId(String name, Long id); @Transactional(timeout = 10) @Modifying @Query("delete from User where name = ?1") void deleteByUserName(String name); }
---JpaRepository
接口本身已经实现了创建(save)、更新(save)、删除(delete)、查询(findAll、findOne)等基本操作的函数,因此对于这些基础操作的数据访问就不需要开发者再自己定义。
6.创建一个controller做测试
@RestController @RequestMapping("/user") public class UserController { @Resource private UserRepository repository; @RequestMapping("/add") public User addUser(@RequestParam(value="name")String name, @RequestParam(value="age")Integer age) { return repository.save(new User(name, age)); } @RequestMapping("/delete") public void delete(@RequestParam(value="id")Long id) { repository.delete(id); } @RequestMapping("/queryAll") public List<User> queryAll() { return (List<User>) repository.findAll(); } @RequestMapping("/queryById") public User queryById(@RequestParam(value="id")Long id) { return repository.findOne(id); } @RequestMapping("/queryByName") public List<User> queryByName(@RequestParam(value="name")String name) { return repository.findByName(name); } }
---
启动即可调试。
补充:
自定义简单查询
自定义的简单查询就是根据方法名来自动生成SQL,支持findBy
,readBy
,queryBy
,countBy
, getBy,deleteBy
后面加属性名称
如User findByUserName(String userName);
可以组合And
、 Or,如
User findByUserNameOrEmail(String username, String email);
可以组合LIKE
、 IgnoreCase
、 OrderBy如:
List<User> findByEmailLike(String email);
User findByUserNameIgnoreCase(String userName);
List<User> findByUserNameOrderByEmailDesc(String email);
--
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 | 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 ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … 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) |
分页查询
分页查询在实际使用中非常普遍了,spring data jpa已经帮我们实现了分页的功能,在查询的方法中,需要传入参数Pageable
,当查询中有多个参数的时候Pageable
建议做为最后一个参数传入
Page<User> findALL(Pageable pageable);
Page<User> findByUserName(String userName,Pageable pageable);
Pageable
是spring封装的分页实现类,使用的时候需要传入页数、每页条数和排序规则
@Test public void testPageQuery() throws Exception { int page=1,size=10; Sort sort = new Sort(Direction.DESC, "id"); Pageable pageable = new PageRequest(page, size, sort); userRepository.findALL(pageable); userRepository.findByUserName("testName", pageable); }
限制数量查询:
ser findFirstByOrderByLastnameAsc(); User findTopByOrderByAgeDesc(); Page<User> queryFirst10ByLastname(String lastname, Pageable pageable); List<User> findFirst10ByLastname(String lastname, Sort sort); List<User> findTop10ByLastname(String lastname, Pageable pageable);
自定义SQL查询
spring data也是支持自定义的SQL查询的;在SQL的查询方法上面使用@Query
注解,删除和修改使用@Modifying
. 也可以根据需要添加 @Transactional
开启事务,查询超时的设置等
@Modifying @Query("update User u set u.userName = ?1 where c.id = ?2") int modifyByIdAndUserId(String userName, Long id); @Transactional @Modifying @Query("delete from User where id = ?1") void deleteByUserId(Long id); @Transactional(timeout = 10) @Query("select u from User u where u.emailAddress = ?1") User findByEmailAddress(String emailAddress);
枚举
如果希望数据库中存储的是枚举对应的String类型,而不是枚举的索引值,需要在属性上面添加@Enumerated(EnumType.STRING)
注解
@Enumerated(EnumType.STRING) @Column(nullable = true) private UserType type;
不需要和数据库映射的属性
在实体类上加入注解@Entity
,会让实体类和表关连,如果其中某个属性不需要和数据库关联,只需要加上@Transient注解
既可。
end