JPA
Spring Data JPA 是 spring data 项目下的一个模块。提供了一套基于 JPA标准操作数据库的简化方案。底层默认的是依赖 Hibernate JPA 来实现的。
JPA的出现主要是为了简化持久层开发以及整合ORM技术,结束Hibernate、TopLink、JDO等ORM框架各自为营的局面。JPA是在吸收现有ORM框架的基础上发展而来,易于使用,伸缩性强。总的来说,JPA包括以下3方面的技术:
- ORM映射元数据: 支持XML和注解两种元数据的形式,元数据描述对象和表之间的映射关系
- API: 操作实体对象来执行CRUD操作
- 查询语言: 通过面向对象而非面向数据库的查询语言(
JPQL
)查询数据,避免程序的SQL语句紧密耦合
版本环境
java:jdk-14.0.1
springboot:v2.3.4.RELEASE
gradle:gradle-6.7-rc-4
IntelliJ IDEA:2020.1.2
spring-boot-starter-data-jpa:v2.3.4.RELEASE
数据源的配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mytest?useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=rootroot
spring.jpa.database=MySQL
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
create
:每次运行程序时,都会重新创建表,故而数据会丢失
create-drop
:每次运行程序时会先创建表结构,然后待程序结束时清空表
upadte
:每次运行程序,没有表时会创建表,如果对象发生改变会更新表结构,原有数据不会清空,只会更新(推荐使用)
validate
:运行程序会校验数据与数据库的字段类型是否相同,字段不同会报错
none
: 禁用DDL处理
实体类
@NoArgsConstructor
@ApiModel(value = "用户实体", description = "用户实体类")
@Data
@Table(name = "user")
@Entity
public class User implements Serializable {
private static final long serialVersionUID = 4728506793752030545L;
@ApiModelProperty(value = "用户名")
@Column(name = "name" )
private String name;
@JsonIgnore
@ApiModelProperty(value = "用户密码")
@Column(name = "pass" )
private String pass;
@ApiModelProperty(value = "用户年龄")
@Column(name = "age" )
private Integer age;
@Column(name = "email" )
@ApiModelProperty(value = "用户邮件")
private String email;
@ApiModelProperty(value = "用户id")
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id" )
private Integer id ;
}
数据库
create table mytest.user
(
id int auto_increment
primary key,
name varchar(30) not null,
pass varchar(30) not null,
age int null,
email varchar(30) null,
constraint user_name_uindex
unique (name)
);
Repository
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
//增
@Transactional(rollbackFor=Exception.class)
@Modifying
@Query(nativeQuery = true, value ="insert into user(name,pass,age,email) values(?1,?2,?3,?4)")
int addUserByName(String name,String pass,int age,String email);
//删
@Transactional(rollbackFor=Exception.class)
@Modifying
@Query(nativeQuery = true, value ="delete from user where name =?1")
int deleteUserByName(String name);
//改
@Transactional(rollbackFor=Exception.class)
@Modifying
@Query(nativeQuery = true, value ="update user set pass=?2 where name =?1")
int updateUserPassByName(String name,String pass);
//查单例
@Query(nativeQuery = true, value ="select id,name,pass,age,email from user where name =?1")
User getUserByName(String name);
//查集合
@Query(nativeQuery = true, value ="select id,name,pass,age,email from user where age <=?1")
List<User> getUsersByAgeMax(int age);
}
测试调用
@RunWith(SpringRunner.class)
@SpringBootTest
public class GradleSpringBootApplicationTests {
@Autowired
UserRepository userRepository;
@Test
public void contextLoads() {
System.out.println(userRepository.deleteUserByName("lzc"));
System.out.println(userRepository.updateUserPassByName("lzc", "960929"));
System.out.println(userRepository.getUserByName("lzc").toString());
System.out.println(userRepository.addUserByName("lzc", "123", 123, "aksjlaklsdf"));
userRepository.getUsersByAgeMax(30).forEach(System.out::println);
}
}
遇到的坑
@Modifying和@Transactional
增删改等操作数据库改变的操作必须加@Modifying和@Transactional(rollbackFor=Exception.class)这两个注解。
当我们要通过自已写的更新、插入、删除SQL语句来实现更新、插入、删除操作时,至少需要用两个步骤:1)@Query来注入我们自定义的sql;2)使用@Modifying来标注是一个更新类的自定义语句。
@Modifying的主要作用是声明执行的SQL语句是更新(增删改)操作,@Transactional的主要作用是提供事务支持(提供例如隔离性等事务特性,JPA默认会依赖JDBC默认隔离级别)。
@Modifying只是声明了这个操作是一个修改操作,但却没有修改这个方法的事务等级,因此这个方法依然不能进行修改操作。只有声明了@Transactional,本质上是声明了@Transactional(readOnly=false),这样覆盖了默认的@Transactional配置便可以执行修改操作了。