【Spring Boot】Spring Boot中的简单查询

前面介绍了在Spring Boot项目中集成JPA框架,实现数据的增、删、改、查等功能。Spring Data JPA的使用非常简单,只需继承JpaRepository即可实现完整的数据操作方法,无须任何数据访问层和SQL语句。JPA除了这些功能和优势之外,还有非常强大的数据查询功能。以前复杂的查询都需要拼接很多查询条件,JPA有非常方便和优雅的方式来解决。接下来就聊一聊JPA的查询功能,从而体验Spring Data JPA的强大。

1.预生成方法

前面介绍了JpaRepository接口实现访问数据库的所有关键接口,比如exists()、save()、findAll()、delete()等方法。创建UserRepository类继承JpaRepository类,拥有父类中所有预先生成的方法。

调用这些方法也特别简单,上面所有JpaRepository父类拥有的方法都可以直接调用,无须声明。示例代码如下:

userRespository.existsByld((long) 1);
userRespository.save(user);
userRespository.findById((long) 1);
userRespository.findAll();
userRespository.delete(user);
userRespository.deleteById((long) 1);

2.自定义简单查询

JPA除了可以直接使用JpaRepository接口提供的基础功能外,还支持根据实体的某个属性实现数据库操作,Spring Data JPA能够根据其方法名为其自动生成SQL,支持的关键字有find、query、get、read、count、delete等,主要的语法是findByXX、queryByXX、getByXX、readByXX、countByXX等。利用这个功能,仅需要在定义的Repository中添加对应的方法名即可,无须具体实现,使用时Spring Data JPA会自动根据方法名来生成SQL语句。

2.1 属性查询

如果想根据实体的name属性来查询User的信息,那么直接在UserRepository中增加一个接口声明即可:

User findByUserName(String userName);

从上面的示例可以看到,我们可以在UserRepository接口中声明findByUserName方法,无须实现,JPA会自动生成对应的实现方法及其SQL语句。

2.2 组合查询

JPA不仅支持单个属性查询,还支持多个属性查询,根据And、Or等关键字进行组合查询,示例代码如下:

User findByNameOrPassword (String name, String password);

在上面的示例中,根据姓名和密码两个属性组合查询,属性名称与个数要与参数的位置与个数一一对应。可以根据查询的条件不断地添加和拼接,Spring Data JPA都可以正确解析和执行。

2.3 JPA关键字

JPA的自定义查询除了And、Or关键字外,基本上SQL语法中的关键字JPA都支持,比如like、between等。

按照Spring Data的规范,查询方法以find、read、get开头。涉及查询条件时,条件的属性用条件关键字进行连接。需要注意的是,条件属性首字母大写。

3.自定义SQL查询

一般的数据查询功能都可以通过定义方法名的方式来实现。但是有些特殊的场景,可能需要自定义的SQL来实现数据查询功能。Spring Data JPA同样可以完美支持,Spring Data JPA提供了@Query注解,通过注解可以自定义HQL或SQL实现复杂的数据查询功能。下面通过示例程序演示@Query注解实现自定义SQL查询。

3.1 HQL查询

在对应查询方法上使用@Query注解,在注解内写HQL来查询内容:

@Query("select u from User u")
List<User> findALL();

在上面的示例中,使用@Query注解定义自定义的HQL语句,实现自定义HQL语句查询。使用HQL比原生的SQL可读性更强,实现面向对象的方式操作数据。使用HQL时需要注意:

1)from后面跟的是实体类,而不是数据表名。

2)查询字段使用的是实体类中的属性,而不是数据表中的字段。

3)select后面不能跟“*”,应为实体类中的属性。

3.2 SQL查询

JPA除了支持HQL语句查询外,还可以直接使用SQL语句,这样比较直观,只需再添加一个参数“nativeQuery = true”即可:

@Query(value="select * from user u where u.name = ?1",nativeQuery = true)
List<User> findByName(String name);

上面示例中的“?1”表示方法参数中的顺序,“nativeQuery = true”表示执行原生SQL语句。除了按照这种方式传参外,还可以使用@Param传值方式:

@Query(value="select u from User u where u.password = :password")
List<User> findByPassword(@Param("password") String password);

3.3 修改和删除

除了自定义查询语句外,@Query注解同样可以用于定义修改和删除语句,只不过还需要加上@Modifying注解。示例代码如下:

@Modifying
@Query("update User set userName = ?1 where id = ?2")
int modifyById(String userName, Long id);

@Modifying
@Query("delete from User where id = ?1")
void deleteUserById(Long id);

在上面的示例中,自定义delete和update语句需要添加@Modifying注解。需要注意的是,使用时需要在Repository或者更上层增加@Transactional注解,确保数据能成功写入数据库。

4.已命名查询

除了使用@Query注解外,还可以使用@NamedQuery与@NameQueries等注解定义命名查询。JPA的命名查询实际上就是给SQL查询语句起一个名字,执行查询时就是直接使用起的名字,避免重复写JPQL语句,使得查询方法能够复用。下面通过示例程序演示JPA已命名查询。

4.1 定义命名查询

在实体类中,@NamedQuery注解定义一个命名查询语句,示例代码如下:

@Entity
@Table(name="user")
@NamedQuery(name="findAllUser", query="SELECT U FROM User u")
public class User {
    
    

}

在上面的示例中,@NamedQuery中的name属性指定命名查询的名称,query属性指定命名查询的语句。如果要定义多个命名查询方法,则需要使用@NamedQueries注解:

@Entity
@Table(name="users")
@NamedQueries({
    
    
        @NamedQuery(name = "findAllUser", query = "SELECT U FROM User u"),
        @NamedQuery(name = "findUserWithId", query = "SELECT U FROM User u WHERE u.id = ?1"),
        @NamedQuery(name = "findUserWithName", query = "SELECT U FROM User u WHERE u.name = :name")
})
public class User {
    
    

}

在上面的示例中,在User实体类中定义了findAllUser()、findUserWithId()、findUserWithName()三种方法。

4.2 调用命名查询

定义命名查询后,可以使用EntityManager类中的createNamedQuery()方法传入命名查询的名称来创建查询:

    @Resource
    EntityManagerFactory emf;
    @Test
    public void testNamedQuery() {
    
    
        EntityManager em = emf.createEntityManager();
        // 根User实体中定义的命名查询
        Query query = em.createNamedQuery("findUserWithName");
        query.setParameter("name", "ysxq");
        List<User> users = query.getResultList();
        for (User u : users) {
    
    
            System.out.println("name:" + u.getName() + ",age:" + u.getAge());
        }
    }

在上面的示例中,使用createNamedQuery创建对应的查询,JPA会先根据传入的查询名查找对应的NamedQuery,然后通过调用getResultList()方法执行查询并返回结果。

除了使用@NamedQuery注解的方式之外,Spring Data JPA提供的Named查询可以支持将SQL语句写至XML文件中,实现SQL与Java代码的分离。在resources/META-INF目录下创建orm.xml文件并定义命名方法,参考配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.0"
                 xmlns="http://java.sun.com/xml/ns/persistence/orm"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
                 http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/persistence/orm_2_2.xsd">
    <named-native-query name="findUserWithName2" result-class="com.example.ysxq.model.User">
        <description>通过name查询用户数据</description>
        <query>select u.id , u.name , u.password , u.age from users u where u.name = :name</query>
    </named-native-query>
</entity-mappings>

在orm.xml文件中使用标签定义queryByName的命名查询,使用XML的方式与使用@NamedQuery注解方式的效果是一样的。只是将SQL语句写至XML文件中,实现SQL与Java代码的分离,使得定义的Java实体类看起来不那么复杂、臃肿。

猜你喜欢

转载自blog.csdn.net/weixin_45627039/article/details/132830831