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配置便可以执行修改操作了。