在Spring Repository中能否使用原始的SQL查询?

145

我需要在Spring Data Repository中使用原生SQL,这是否可行? 我看到所有关于@Query的内容都是基于实体的。


SqlQuery可以吗?http://static.springsource.org/spring/docs/2.5.x/api/ - Chetter Hummin
我该如何在代码库中使用它?还是说我不需要使用代码库,只需在我的服务中使用该对象? - Ben
你使用spring-data-jpa吗? - zagyi
@Webnet 我自己对Spring有点新,但是在我看来,你可以将其用作一个对象。 - Chetter Hummin
你尝试过使用Spring JDBCTemplate吗? - BlackJoker
6个回答

159

{@code @Query}注解允许将native queries设置为true以执行本地查询。

引用自Spring Data JPA的参考文档

此外,查看此部分以了解如何使用命名本地查询进行操作。


22
@user454322,参数从1开始,所以应该是:@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true) - Jacob van Lingen
nativeQuery = true 使我免于遭受非法参数异常的困扰。 - Reza

69

1. 通过CrudRepository(投影)

使用查询方法时,Spring Data Repositories通常返回域模型。然而,有时候,由于各种原因,您可能需要更改该模型的视图。 —来源

假设您的实体如下:

    import javax.persistence.*;
    import java.math.BigDecimal;
    
    @Entity
    @Table(name = "USER_INFO_TEST")
    public class UserInfoTest {
        private int id;
        private String name;
        private String rollNo;
    
        public UserInfoTest() {
        }

        public UserInfoTest(int id, String name) {
        this.id = id;
        this.name = name;
        }
     
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "ID", nullable = false, precision = 0)
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        @Basic
        @Column(name = "name", nullable = true)
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Basic
        @Column(name = "roll_no", nullable = true)
        public String getRollNo() {
            return rollNo;
        }
    
        public void setRollNo(String rollNo) {
            this.rollNo = rollNo;
        }
    }

现在你的 Projection 类如下所示。它可以包含你需要的那些字段。

public interface IUserProjection {
     int getId();
     String getName();
     String getRollNo();
}

而且您的数据访问对象(Dao)如下所示

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;

import java.util.ArrayList;

public interface UserInfoTestDao extends CrudRepository<UserInfoTest,Integer> {
    @Query(value = "select id,name,roll_no from USER_INFO_TEST where rollNo = ?1", nativeQuery = true)
    ArrayList<IUserProjection> findUserUsingRollNo(String rollNo);
}

现在ArrayList<IUserProjection> findUserUsingRollNo(String rollNo)将给您用户列表。

2. 使用EntityManager

假设您的查询是“select id、name from users where roll_no = 1001”。

这里查询将返回一个带有id和name列的对象。您的响应类如下:

您的响应类如下:

public class UserObject{
        int id;
        String name;
        String rollNo;

        public UserObject(Object[] columns) {
            this.id = (columns[0] != null)?((BigDecimal)columns[0]).intValue():0;
            this.name = (String) columns[1];
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getRollNo() {
            return rollNo;
        }

        public void setRollNo(String rollNo) {
            this.rollNo = rollNo;
        }
    }

这里的UserObject构造函数将获取一个对象数组,并使用该对象设置数据。

public UserObject(Object[] columns) {
            this.id = (columns[0] != null)?((BigDecimal)columns[0]).intValue():0;
            this.name = (String) columns[1];
        }

你的查询执行函数如下:

public UserObject getUserByRoll(EntityManager entityManager,String rollNo) {

        String queryStr = "select id,name from users where roll_no = ?1";
        try {
            Query query = entityManager.createNativeQuery(queryStr);
            query.setParameter(1, rollNo);

            return new UserObject((Object[]) query.getSingleResult());
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

在这里,您需要导入以下软件包:

import javax.persistence.Query;
import javax.persistence.EntityManager;

现在你的主类,你必须调用这个函数。首先获取EntityManager并调用这个getUserByRoll(EntityManager entityManager,String rollNo)函数。调用过程如下:

这是导入

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

通过这种方式获取 EntityManager

@PersistenceContext
private EntityManager entityManager;

UserObject userObject = getUserByRoll(entityManager,"1001");

现在你在这个userObject中有数据。
注意:
query.getSingleResult()返回一个对象数组。您必须保持查询列位置和数据类型与查询列位置相同。
select id,name from users where roll_no = 1001 

查询返回一个数组,其中 [0] --> id 和 [1] -> name

更多信息请访问 threadthis Thread

谢谢 :)


getUserByRoll() 的选项 Kaiser、Dinner、无麸质、Bap、Challah j/k。 - dbinott
非常感谢你在选项#2中清晰的解释。关于如何在UserObject上设置rollNo,可能有些不太明显。我猜想你需要直接调用setter方法来设置。这并没有对我造成任何困扰,但可能会使答案稍微更加清晰一些。无论如何,非常感谢你的帮助。 - undefined

7
我们可以使用createNativeQuery(“这里是本地SQL查询”);
例如:
Query q = em.createNativeQuery("SELECT a.firstname, a.lastname FROM Author a");
List<Object[]> authors = q.getResultList();

29
如果您展示如何创建 em 变量,将会更加有用/完整。 - ETL
2
em是"javax.persistence.EntityManager"。在我的情况下,我只需使用@Autowired注入它即可。 - Yasitha Bandara
2
是的。EntityManager 类 - Lova Chittumuri

6

在Spring Repository中可以使用原始查询。

      @Query(value = "SELECT A.IS_MUTUAL_AID FROM planex AS A 
             INNER JOIN planex_rel AS B ON A.PLANEX_ID=B.PLANEX_ID  
             WHERE B.GOOD_ID = :goodId",nativeQuery = true)

      Boolean mutualAidFlag(@Param("goodId")Integer goodId);

6
这是您可以在简单表单中使用的方法。
@RestController
public class PlaceAPIController {

    @Autowired
    private EntityManager entityManager;

    @RequestMapping(value = "/api/places", method = RequestMethod.GET)
    public List<Place> getPlaces() {
        List<Place> results = entityManager.createNativeQuery("SELECT *  FROM places p limit 10").getResultList();
        return results;
    }
}

1
这是一个简单的解决方案,对我很有效!不知道它是否有一些缺点,因为我们这里没有使用服务和存储库层。 - Phaki

4

您也可以使用Spring Data JDBC来访问数据库,它是基于Spring Data Commons的完全支持Spring项目,可以使用原始SQL而无需使用JPA。

它比Spring Data JPA功能较弱,但如果您想要一个轻量级的解决方案用于简单项目,而不使用像Hibernate这样的ORM,则值得一试。


Spring Data JDBC 代码库最近一次提交是在2016年。 - Mass Dot Net
1
很好的发现,我已经更新了推荐,建议使用 Spring 官方支持的 https://spring.io/projects/spring-data-jdbc。 - Sébastien Deleuze
你的清单中还需要考虑另一项(我刚刚偶然发现的):JDBI。它不是ORM,而是一个建立在JDBC之上的层,可以让你更简洁地编写查询语句,并提供诸如添加参数时的SQL注入保护等便利功能。 - Mass Dot Net

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接