上篇学习了mybaits的使用,既可以通过注解方式实现,也可以使用常见的xml配置方式实现
这篇我们继续学习数据库访问层jpa,集各家所长,各取所需吧
一,第一步当然还是引入相关依赖包,在pom.xml中继续添加:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
二,jpa底层是由Hibernate来实现的,需要在application.properties中添加相关配置
#jpa
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql= true
spring.jackson.serialization.indent_output=true
这里说明一下:
hibernate.hbm2ddl.auto参数的作用主要用于:自动创建|更新|验证数据库表结构,有四个值:
create: 每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,
哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。
create-drop :每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。
update:最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),
以后加载hibernate时根据 model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。
要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等 应用第一次运行起来后才会。
validate :每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值
另外新建sql脚本,命名schema.sql,并放在classpath下面,那么在应用启动的时候会在结束前读取脚本,执行命令
三,测试,我们新建实体类UserInfo,启动查看是否自动创建了table
package com.example.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
@Entity
@Table(name="user_info")
public class UserInfo {
@Id
@GeneratedValue
private long id;
private String name;
private String gender;
/** 不映射成数据表 */
@Transient
private String status;
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 String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
四,启动查看,数据库创建了空的table,user_info
五,加入schema.sql脚本,重新启动
insert into user_info (name,gender) values('initname','M');
再查看数据库,此时已成功插入一条初始化数据,这里需要注意两点:
1,开始我引入的spring-boot-starter-parent版本是1.3.8的,前面都没问题,
引入jpa后项目就报错了,查看本地仓库,依赖包也下载下来了,不知道什么原因,
于是更改parent版本为1.3.6,成功启动
2,执行schema.sql脚本,前提是已经创建好了table,自动创建table是应用第一次启动结束后才会创建
而读取脚本文件是在应用启动结束前,如果没有创建table就加入脚本文件,会找不到table报错,另外每次重启都会执行一次。
六,创建UserInfoRepository 继承Repository接口,基本方法已经有实现,继承后能直接使用
这也是使用jpa的便利之处:
package com.example.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.entity.UserInfo;
public interface UserInfoRepository extends JpaRepository<UserInfo, Long>{
}
七,创建UserController,这里简化了代码,没有使用service层,仅供测试用
package com.example.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.example.entity.UserInfo;
import com.example.repository.UserInfoRepository;
@RestController
public class UserController {
@Autowired
private UserInfoRepository userRepository;
@RequestMapping(value="/user/save",method=RequestMethod.GET)
public void save(){
UserInfo user = new UserInfo();
user.setGender("F");
user.setName("wendy");
userRepository.save(user);
}
}
八,查看控制台打印sql语句:
2017-04-07 17:09:01.728 INFO 516 --- [nio-8088-exec-1] o.a.c.c.C.[.[localhost].[/spring-boot] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2017-04-07 17:09:01.729 INFO 516 --- [nio-8088-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2017-04-07 17:09:01.761 INFO 516 --- [nio-8088-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 32 ms
Hibernate: insert into user_info (gender, name) values (?, ?)
九,除了封装好的方法,我们也可以自定义查询,jpa会根据方法名自动创建sql语句
如,在UserInfoRepository中添加方法:
package com.example.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.entity.UserInfo;
public interface UserInfoRepository extends JpaRepository<UserInfo, Long>{
UserInfo findById(long id);
UserInfo findByName(String name);
}
在UserController中新增测试方法:
@RequestMapping(value="/user/id",method=RequestMethod.GET)
public UserInfo findById(long id){
return userRepository.findById(id);
}
@RequestMapping(value="/user/name",method=RequestMethod.GET)
public UserInfo findByName(String name){
return userRepository.findByName(name);
}
测试返回结果如下:
再查看控制台打印的sql语句:
Hibernate: select userinfo0_.id as id1_0_, userinfo0_.gender as gender2_0_, userinfo0_.name as name3_0_ from user_info userinfo0_ where userinfo0_.id=?
Hibernate: select userinfo0_.id as id1_0_, userinfo0_.gender as gender2_0_, userinfo0_.name as name3_0_ from user_info userinfo0_ where userinfo0_.name=?
十,很多时候我们需要根据业务需求写sql语句,下面我们来看如何使用注解写sql语句
如,在UserInfoRepository中添加方法:
/**
* 自定义查询语句
* @param id
* @return
*/
@Query("select gender from UserInfo where id=?1")
String userGender(long id);
/**
* 自定义更新语句
* @param firstname
* @param lastname
* @return
*/
@Transactional
@Modifying
@Query("update UserInfo set name =:name where id =:id")
int updateName(@Param("name")String name,@Param("id")Long id);
这里需要注意:
1,查询表名UserInfo对应的是实体类名,不是数据库表名
2,更新数据库操作,需要添加事务注解@Transactional,否则会报错:
javax.persistence.TransactionRequiredException
3,其他用法可以参见博客:http://jishiweili.iteye.com/blog/2088265
在UserController中新增测试方法:
/**
* 使用注解写查询语句
* @param id
* @return
*/
@RequestMapping(value="/gender",method=RequestMethod.GET)
public String getGender(long id){
return userRepository.userGender(id);
}
/**
* 使用注解生成自定义方法
* @param id
* @return
*/
@RequestMapping(value="/update",method=RequestMethod.POST)
public String update(@RequestBody UserInfo userInfo){
String name = userInfo.getName();
Long id = userInfo.getId();
int count = userRepository.updateName(name,id);
return "成功更新"+count+"条数据";
}
启动测试:
http://localhost:8088/spring-boot/gender?id=1 ========== 返回结果:M
http://localhost:8088/spring-boot/update === params:{"name":"acc","id":"2"} ======= 返回结果:成功更新1条数据
===============================================================================================
jpa的使用就初步演示到这里,下篇我们继续学习日志框架,SpringBoot 学习记录(四): slf4j+logback