JPA原生sql查询

JPA原生SQL查询实践
本文详细介绍了如何使用Java Persistence API (JPA)执行原生SQL查询,包括查询对象数组、实体集合、单个属性及多个属性的方法,并提供了具体的代码示例。

package com.cndatacom.jpa.entity;

 

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import javax.persistence.Table;

 

@Entity

@Table(name="t_user")

public class User {

     

    /**

     * 主键

     */

    @Id

    @GeneratedValue

    private Long id;

     

    /**

     * 名字

     */

    @Column(name="name",length=50)

    private String name;

     

    /**

     * 密码

     */

    @Column(name="password",length=20)

    private String password;

     

    /**

     * 邮箱

     */

    @Column(name="email",length=50)

    private String email;

     

    /**

     * 年龄

     */

    @Column(name="age",length=3)

    private int age;

     

    public User() {

         

    }

     

    //以下省略getter/setter方法

    //......

 

 

         

}

测试:

 

package com.cndatacom.jpa.test;

 

import java.util.List;

 

import javax.persistence.EntityManager;

import javax.persistence.EntityManagerFactory;

import javax.persistence.Persistence;

import javax.persistence.Query;

 

import org.junit.After;

import org.junit.Before;

import org.junit.Test;

 

import com.cndatacom.jpa.entity.User;

 

 

/**

 * 测试JPA原生SQL查询

 * @author Luxh

 */

public class TestNativeQuery {

EntityManagerFactory emf = null;

     

    @Before

    public void before() {

        //根据在persistence.xml中配置的persistence-unit name 创建EntityManagerFactory

        emf = Persistence.createEntityManagerFactory("myJPA");

    }

     

    @After

    public void after() {

        //关闭EntityManagerFactory

        if(null != emf) {

            emf.close();

        }

    }

     

         

    /**

     * 查询的结果是对象数组的集合

     */

    @Test

    public void testNativeQuery1() {

        EntityManager em = emf.createEntityManager();

        //定义SQL

        String sql = "SELECT * FROM t_user";

        //创建原生SQL查询QUERY实例

        Query query =  em.createNativeQuery(sql);

        //执行查询,返回的是对象数组(Object[])列表,

        //每一个对象数组存的是相应的实体属性

        List objecArraytList = query.getResultList();

        for(int i=0;i<objecArraytList.size();i++) {

            Object[] obj = (Object[]) objecArraytList.get(i);

           //使用obj[0],obj[1],obj[2]...取出属性         

        }

        em.close();

    }

     

     

    /**

     * 查询的结果是实体的集合

     */

    @Test

    public void testNativeQuery2() {

        EntityManager em = emf.createEntityManager();

        //定义SQL

        String sql = "SELECT * FROM t_user";

        //创建原生SQL查询QUERY实例,指定了返回的实体类型

        Query query =  em.createNativeQuery(sql,User.class);

        //执行查询,返回的是实体列表,

        List<User> userList = query.getResultList();

         

        em.close();

    }

     

     

    /**

     * 查询单个属性

     * 返回的是这个属性值的集合

     */

    @Test

    public void testNativeQuery3() {

        EntityManager em = emf.createEntityManager();

        //定义SQL

        String sql = "SELECT t.name FROM t_user t";

        //创建原生SQL查询QUERY实例

        Query query =  em.createNativeQuery(sql);

        //执行查询,返回的是String类型的集合,因为name这个属性是String类型

        List<String>  resultList = query.getResultList();

        em.close();

    }

     

     

    /** 

       * 查询多个属性

       * 返回的是这些属性值的数组的集合

       */  

    @Test  

    public void testNativeQuery4() {   

        EntityManager em = emf.createEntityManager();  

        //定义SQL        

        String sql = "SELECT t.name,t.age,t.email FROM t_user t";      

        //创建原生SQL查询QUERY实例     

        Query query =  em.createNativeQuery(sql);      

        //执行查询,返回的是查询属性值数组的集合      

        List objecArraytList = query.getResultList();

        for(int i=0;i<objecArraytList.size();i++) {     

            Object[] obj = (Object[]) objecArraytList.get(i);

             //使用obj[0],obj[1],obj[2]取出属性

        }      

        em.close();

         

    }

     

}

 

### 3.1 使用原生 SQL 查询的方法 在 JPA 中,可以通过 `EntityManager` 的 `createNativeQuery` 方法执行原生 SQL 查询。该方法允许开发者直接编写 SQL 语句,并通过 JPA 与数据库交互。原生 SQL 查询适用于需要对数据库操作进行更细粒度控制的场景,例如复杂的查询逻辑或数据库特定功能的使用。 一个基本的原生 SQL 查询示例如下: ```java String sql = "select t.class_no from t_student t where t.class_no =:class_no"; Query query = em.createNativeQuery(sql); query.setParameter("class_no", 20); List<Object> objecArraytList = query.getResultList(); ``` 通过 `getResultList()` 方法可以获取查询结果的 `List`,其中每个元素的类型为 `Object`。如果查询结果只包含单个字段,则可以直接将每个元素转换为目标类型,如 `BigDecimal` 或 `String` [^1]。 ### 3.2 查询多个字段与映射到实体类 当原生 SQL 查询返回多个字段时,可以将结果映射到实体类或自定义的 DTO(Data Transfer Object)对象中。例如,查询 `t_student` 表中的 `class_no`、`student_no` 和 `remark` 字段: ```java String sql = "select t.class_no ,t.student_no ,t.remark from t_student t where t.class_no =:class_no"; Query query = em.createNativeQuery(sql); query.setParameter("class_no", 20); List<Object[]> result = query.getResultList(); ``` 此时,`getResultList()` 返回的是一个 `List<Object[]>`,其中每个 `Object[]` 对应一行数据。如果需要将结果转换为特定的实体类或 DTO,可以通过遍历 `Object[]` 并手动映射字段值。 ### 3.3 使用 `@SqlResultSetMapping` 注解进行结果映射 为了简化原生 SQL 查询结果的映射过程,可以使用 `@SqlResultSetMapping` 注解定义查询结果与实体类之间的映射关系。例如,定义一个 `User` 实体类并将其映射到查询结果: ```java @Entity @Table(name = "t_user") @SqlResultSetMapping(name = "UserMapping", entities = @EntityResult(entityClass = User.class)) public class User { // 实体字段定义 } ``` 然后在查询中使用该映射: ```java String sql = "select * from t_user where age > 20"; Query query = em.createNativeQuery(sql, "UserMapping"); List<User> users = query.getResultList(); ``` 这样,查询结果可以直接映射为 `User` 类型的列表,从而避免手动处理字段映射 [^2]。 ### 3.4 使用分页与排序 在实际应用中,通常需要对查询结果进行分页和排序。可以通过 `Pageable` 和 `Sort` 实现这一功能。例如: ```java Sort sort = Sort.by(Sort.Direction.DESC, "id"); Pageable pageable = PageRequest.of(0, 2, sort); Page<Article> result = articleRepository.queryArticleList(title, pageable); ``` 此方法适用于 Spring Data JPA 提供的仓库接口,能够方便地实现分页查询 [^4]。 ### 3.5 最佳实践 1. **避免 SQL 注入**:在构造原生 SQL 查询时,应使用参数化查询(如 `setParameter`)来防止 SQL 注入攻击。 2. **优化查询性能**:对于复杂的查询,建议使用数据库索引或优化 SQL 语句,以减少数据库负载。 3. **合理使用实体映射**:如果查询结果可以直接映射到实体类,则应优先使用 `@SqlResultSetMapping`,以提高代码可读性和可维护性。 4. **处理多字段结果**:当查询返回多个字段时,应考虑使用 DTO 或 `Object[]` 来封装结果,避免直接操作原始数据。 5. **使用事务管理**:对于涉及数据修改的原生 SQL 查询,应确保操作在事务中执行,以保证数据一致性。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值