JPA in action

Common ORM frameworks

Mybatis (ibatis): An excellent persistence layer framework that supports custom SQL, stored procedures, and advanced mapping. MyBatis avoids almost all JDBC code and manually setting parameters and getting result sets. MyBatis can use simple XML or annotations to configure and map native information, and map interfaces and Java POJOs (Plain Ordinary Java Objects, ordinary Java objects) into records in the database.
  Hibernate: An open source object-relational mapping framework, which encapsulates JDBC with a very lightweight object, and establishes a mapping relationship between POJO and database tables. It is a fully automatic ORM framework. Hibernate can automatically generate SQL statements. Automatic execution allows Java programmers to use object programming thinking to manipulate the database as they wish.
  Jpa: The abbreviation of Java Persistence API, the Chinese name is Java Persistence Layer API, which is JDK 5.0 annotation or XML description object-relational table mapping relationship, and persists the entity object in the runtime to the database.

1. Introduction to Spring data JPA

Spring data JPA is a set of JPA application framework encapsulated by Spring on the basis of ORM framework and JPA specification, and provides a complete set of data access layer solutions.

Second, the function of Spring data JPA

The function of Spring data JPA is very powerful, here we skip the step of setting up the environment first, to see the "beauty" of Spring data JPA.

Spring data JPA provides users with the following interfaces:

  1. Repository: It is just a logo, indicating that anyone who inherits it is a warehouse interface class, which is convenient for Spring to automatically scan and identify
  2. CrudRepository: Inherit Repository and implement a set of CRUD-related methods
  3. PagingAndSortingRepository: Inherit CrudRepository and implement a set of methods related to paging sorting
  4. JpaRepository: Inherit PagingAndSortingRepository to implement a set of JPA specification-related methods
  5. JpaSpecificationExecutor: It is special and does not belong to the Repository system. It implements a set of methods related to JPA Criteria query.

3. Spring Data JPA's support for transactions

By default, methods implemented by Spring Data JPA use transactions. The method for the query type is equivalent to @Transactional(readOnly=true); the method for adding, deleting and modifying the type is equivalent to @Transactional. It can be seen that, except for setting the query method as a read-only transaction, other transaction attributes adopt default values.

If the user finds it necessary, the transaction attribute can be explicitly specified using @Transactional on the interface method, which overrides the default value provided by Spring Data JPA. At the same time, developers can also use @Transactional to specify transaction attributes on the business layer method, which is mainly for the case where a business layer method calls the persistence layer method multiple times. The transaction of the persistence layer will decide whether to suspend the transaction of the business layer or join the transaction of the business layer according to the transaction propagation behavior set.

Four, JPA custom SQL

As the name suggests, based on the name of the method, you can create a query

As long as you inherit the JpaRepository<Object,Integer> interface, you can implement custom SQL. It is best to use this query for simple queries.

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 findByFirstname,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<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> 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)

5. What annotations does JPA have?

Note: JPA can automatically generate tables based on entity class attributes, just add the following annotations

@Entity
@Table(name = “”)
@Column(name = “”)

annotation explain
@Entity Declare the class as an entity or a table.
@Table Declare the table name.
@Id Specifies the attribute of the class used for identification (primary key in a table).
@GeneratedValue Specifies how the ID property can be initialized, such as automatically, manually, or with a value obtained from a sequence table.
@Column Specifies the persistent property column properties.
@Transient Specifies a property that is not persistent, ie: the value is never stored in the database.
@Basic Specify individual fields that are not constrained explicitly.
@Embedded Specifies the class or attribute whose value is an instance of an embeddable class entity.
@SequenceGenerator Specifies the value of the property specified in the @GeneratedValue annotation. It creates a sequence.
@TableGenerator Specifies the value generator for the property specified in the @GeneratedValue annotation. It creates a generated table of values.
@AccessType This type of annotation is used to set the access type. If you set @AccessType(FIELD), you can access the variable directly and don't need getter and setter, but it must be public. If @AccessType(PROPERTY) is set, Entity variables are accessed through getter and setter methods.
@JoinColumn Specifies an entity organization or collection of entities. This is used in many-to-one and one-to-many associations.
@UniqueConstraint Specify fields and unique constraints for primary or secondary tables.
@ColumnResult Refer to column names in SQL queries using the select clause.
@ManyToMany Defines a many-to-many-to-many relationship between joined tables.
@ManyToOne Defines a many-to-one relationship between joined tables.
@OneToMany Defines a one-to-many relationship between the join tables.
@OneToOne There is a one-to-one relationship between the join tables defined.
@NamedQueries Specifies a list of named queries.
@NamedQuery Specifies a query using a static name.

了解了注解之后我们来看看如何使用吧

六、SQL能力

1. JPA有两种SQL查询方式

因为接口继承了JpaRepository<Object,Integer>接口,所以接口可以实现里面的所有方法

JPA的查询语言是面向对象而非面向数据库的,他以面向对象的自然语法构造查询语句,可以看成是Hibernate HQL的等价物。JPA定义了独特的JPQL(Java Persistence Query Language),JPQL是EJB QL的一种扩展,它是针对实体的一种查询语言,操作对象是实体,而不是关系数据库的表,而且能够支持批量更新和修改、JOIN、GROUP BY、Having 等通常只有SQL才能够提供的高级查询特性,甚至还能够支持子查询。

原生SQL

原生SQL,顾名思义就是数据库原原本本的SQL语句,可以把SQL语句复制出来到数据库直接运行

/**
  * 获取用户信息
  * nativeQuery = true:使用sql查询
  * nativeQuery = false:使用jpql查询,默认就是false
  */
@Query(value = "select * from users where username=?", nativeQuery = true)
Users findByUsername(String username);

JPQL查询

JPQL查询使用的是实体类属性

@Query(value = "select u.id,u.name from users u where u.username=?")
Users findByUsername(String username);
注意:使用如下SQL需要定义实体类构造函数,并且参数顺序一致
@Query("select new com.example.demo.entity.TestDemo(t.id,t.username,t.testTime) from  TestDemo t")
List<TestDemo> testAll();

2. 传参方式

下表索引传参
@Query ( "select u from users u where id>?1 and username like %?2%" )
List <User > selectUserByParam ( Long id , String name );

@param 命名参数传参
@Query ( "select u from users u where id>:id and username like :name" )
List <User > selectUserByParam ( @param('id') Long id ,  @param('name') String name );

对象传参
@Query ( "select u from users u where id>:#{#users.id} and username like :#{#users.name}" )
List <User> selectUserByParam2 (Users users);

3. 动态SQL

是不是跟Mybatis的动态SQL有点相识,只不过这里是判断是否为空,为空了就不会往下走了,不为空就执行SQL将参数传进去进行查询

@Query("select t from  TestDemo t where ((?1 is null or ?1 = '') or (?2 is null or ?2 = '') or (t.testTime between ?1 and ?2)) ")
Page<TestDemo> testAll1(String startTime, String endTime, Pageable pageable);

4. 两表联合分页查询

注意JPA原生SQL和Pageable配合会报错

JPA原生SQL和Pageable配合报错解决:https://blog.csdn.net/ITKidKid/article/details/130167244

这里只是做个示例,随便写的,具体根据实际情况开发

数据访问层 testRepository 接口

@Query("select new com.example.demo.vo.UserAddressVo(u.id,a.province,a.city,a.area) from  User u inner join Address a on u.id = a.userId")
Page<UserAddressVo> pageAll(Pageable pageable);

业务逻辑层 testServiceImpl 接口实现类

testRepository.pageAll(PageRequest.of(page - 1, limit, Sort.Direction.DESC, "createDate"));

七、项目实战

1. 导入依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mysql-->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>8.0.28</version>
</dependency>
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.18.26</version>
	<scope>compile</scope>
</dependency>

2. 生成代码

JPA代码生成:https://www.cnblogs.com/cl-rr/p/10397107.html

可以使用eazycode代码生成器生成代码,也可以使用我上面的这个链接,不过有些地方需要补全

3. 代码编写

控制层
/**
 * (TestDemo)表控制层
 *
 * @author makejava
 * @since 2023-04-26 14:32:35
 */
@RestController
@RequestMapping("/testDemo")
public class TestDemoController {
    
    
	@GetMapping("/testAll")
	public RespBean testAll(@RequestParam(required = false) String startTime,
                                                    @RequestParam(required = false) String endTime) {
    
    
		return RespBean.success("成功",testDemoService.testAll(startTime,endTime));
	}
}

业务逻辑层
接口方法
public interface TestDemoService  {
    
    
	List<TestDemo> testAll(String startTime, String endTime);
}
接口方法实现   
@Service
public class TestDemoServiceImpl implements TestDemoService {
    
        
    @Autowired
    private TestDemoRepository rep;
    @Override
    public List<TestDemo> testAll(String startTime, String endTime) {
    
    
        return rep.testAll(startTime,endTime);
    }
}

业务访问层
@Repository
public interface TestDemoRepository extends JpaRepository<TestDemo, Integer> {
    
    
    @Query("select new com.example.demo.entity.TestDemo(t.id,t.username,t.testTime) from  TestDemo t where ((?1 is null or ?1 = '') or (?2 is null or ?2 = '') or (t.testTime between ?1 and ?2)) ")
    List<TestDemo> testAll(String startTime, String endTime);
}

看下结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IV2dz79j-1682650502112)(E:\PRD\Images\image-20230428102649500.png)]

Java全局日期类型转换配置:https://blog.csdn.net/ITKidKid/article/details/130421992

感谢:https://blog.csdn.net/wujiaqi0921/article/details/78789087

https://www.cnblogs.com/cl-rr/p/10397107.html

Guess you like

Origin blog.csdn.net/ITKidKid/article/details/130422071