使用Spring Boot Framework对基于Spring JPA的DAO进行分层的正确方法

时间:2015-04-01 00:48:49

标签: spring hibernate jpa hql spring-boot

Spring Boot& amp; JPA ...

假设我有两个实体映射到两个表,这两个表在数据库中连接。

学生 - 1 ------<道菜的

此外,我们假设已经创建并填充了数据库。

这表明一个学生有很多课程......

我的学生实体:

@Entity
public class Student {

    @OneToMany(mappedBy="student")
    private List<Courses> courses;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "Student_Id")
    private long studentId;

    @Column(name = "Student_Name")
    private String studentName;

    protected Student() { }

    // Getters & Setters
}

我的课程实体:

@Entity
public class Course {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "Course_Id")
    private long courseId;

    @Id
    @Column(name = "Student_Id")
    private long studentId;

    @ManyToOne
    @PrimaryKeyJoinColumn(name="Student_Id", referencedColumnName="Student_Id")
    private Student student;

    @Column(name = "Course_Name")
    private String courseName;

    // Getters & Setters

}

在Spring Boot的教程指南中,它说明了如何扩展CrudRepository接口,但是 它没有指定如何设置一个基于Spring的DAO,它包含在其中使用HQL和EntityManager的自定义查找程序方法。

以下DAO和DaoImpl是否正确?

public interface CourseDao {
    List<Course> findCoursesByStudentName(String studentName);
}

@Repository
public class CourseDaoImpl implements CourseDao {

    @PersistenceContext
    EntityManager em;

    public List<Course> findCoursesByStudentName(String studentName) {
        String sql = "select c.courseName" +
                     "from Course c, Student s " +
                     "where c.course_id = s.student_id " +
                     "and s.studentName = :studentName ";

        Query query = em.createQuery(sql);
        query.setParameter("studentName", studentName);
        return query.getResultList();
    }
}   

然后在客户端代码中,例如,在主类中:

 public class Application {

    @Autowired
    CustomerDao dao;

    public static void main (String args []) {
        List<Course> courses = dao.findCoursesByStudentName("John");
    }   
 }

这是在Spring DAO中使用HQL的标准方法吗?我已经看到@Transactional注释的示例被添加到DAO类的impl(例如CustomerDAOImpl)之前?

如果这是构建我的Spring Boot应用程序的写入方式,或者我应该仅扩展/添加到CrudRepository,请告诉我?

如果有人可以更正我的示例并指向我使用已加入的实体来讨论HQL的URL,我将非常感激。

Spring Boot指南没有描述连接或DAO - 我只需要学习如何正确创建查找返回列表或数据结构的select语句的finder方法。

感谢您花时间阅读此内容......

2 个答案:

答案 0 :(得分:11)

如果我理解你的问题是正确的,你有两个问题:

  1. 如何创建DAO和DAOImpl?
  2. 在哪里放置您的交易注释?
  3. 关于第一个问题,我想指出这是spring-data-jpa使用Hibernate作为JPA提供程序的问题,而不是spring-boot

    使用Spring数据我通常会完全跳过创建DAO,但直接使用自定义存储库扩展标准的CrudRepository。因此,在您的情况下,您甚至不必编写更多代码:

    @Repository
    public interface StudentRepository extends CrudRepository<Student, Long> {
    
        List<Student> findByStudentName(String studentName);
    
    }
    

    这将是足够的,如果您使用

    ,Spring Data将使用正确的实现来填充它
    @Autowired
    StudentRepository studentRepo; 
    

    在您的服务类中。这是我通常用@Transactional注释我的方法的地方,以确保一切都按预期工作。

    关于你关于HQL的问题,请查看spring data jpa documentation,其中指出,对于大多数情况,在界面中坚持使用正确的命名方法或者进行命名查询就足够了(第3.3节) .3)或使用@Query注释(第3.3.4节)手动定义查询,例如应该工作(没试过):

    @Repository
    public interface @CourseRepository extends CrudRepository<Course, Long> {
    
        @Query("select c.courseName from Course c, Student s where c.course_id = s.student_id and s.studentName = :studentName")
        public List<Course> findCoursesByStudentName(String studentName);
    
    }
    

答案 1 :(得分:1)

如果您使用CourseDaoImpl注释@Transactional(假设您已正确定义JpaTransactionManager)您可以只检索具有匹配名称的学生并调用getCourses()方法懒惰加载附属于该学生的课程。由于findCoursesByStudentName将在一个交易中运行,因此它会很好地加载课程。

@Repository
@Transactional(readOnly=true)
public class CourseDaoImpl implements CourseDao {

    @PersistenceContext
    EntityManager em;

    public List<Course> findCoursesByStudentName(String studentName) {
        String sql = "select s " +
                     "from Student s " +
                     "where s.studentName = :studentName ";

        Query query = em.createQuery(sql);
        query.setParameter("studentName", studentName);
        User user = query.getSingleResult();
        if(user != null) {
            return user.getCourses();
        }

        return new ArrayList<Course>();
    }
}