获取超出需要的数据更容易导致性能损失。使用DTO可以让我们只提取所需的数据。在这个应用程序中,我们依赖于Hibernate ResultTransformer和原生SQL生成DTO?
对于不可变的DTO值对象和可变的DTO对象使用不同的方式,不可变的DTO值对象是final字段,因此不能有setter字段:
public class CarDtoNoSetters implements Serializable {
private static final long serialVersionUID = 1L;
private final String name; private final String color;
public CarDtoNoSetters(String name, String color) { this.name = name; this.color = color; }
public String getName() { return name; }
public String getColor() { return color; }
@Override public String toString() { return "CarDtoNoSetters{" + "name=" + name + ", color=" + color + '}'; } }
|
可变的DTO对象:
public class CarDtoWithSetters implements Serializable {
private static final long serialVersionUID = 1L; private String name; private String color;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getColor() { return color; }
public void setColor(String color) { this.color = color; }
@Override public String toString() { return "CarDtoWithSetters{" + "name=" + name + ", color=" + color + '}'; } }
|
编写自己的DAO类,对于不可变的DTO值对象使用ResultTransformer+AliasToBeanConstructorResultTransformer,可变的使用ResultTransformer+Transformers.aliasToBean():
@Repository @Transactional public class Dao<T, ID extends Serializable> implements GenericDao<T, ID> { @PersistenceContext private EntityManager entityManager;
@Transactional(readOnly = true) public List<CarDtoNoSetters> fetchCarsNoSetters() { Query query = entityManager .createNativeQuery("select name, color from car") .unwrap(org.hibernate.query.NativeQuery.class) .setResultTransformer( new AliasToBeanConstructorResultTransformer( CarDtoNoSetters.class.getConstructors()[0] ) ); List<CarDtoNoSetters> result = query.getResultList(); return result; } @Transactional(readOnly = true) public List<CarDtoWithSetters> fetchCarsWithSetters() { Query query = entityManager .createNativeQuery("select name, color from car") .unwrap(org.hibernate.query.NativeQuery.class) .setResultTransformer( Transformers.aliasToBean(CarDtoWithSetters.class) );
List<CarDtoWithSetters> result = query.getResultList(); return result; } protected EntityManager getEntityManager() { return entityManager; } }
|
使用EntityManager.createNativeQuery()和unwrap(org.hibernate.query.NativeQuery.class)- 从Hibernate 5.2开始,ResultTransformer不推荐使用,但是直到可以使用替换(在Hibernate 6.0中)它可以使用(进一步阅读)
使用JPQL和原生SQL在SQL语句上稍微有点不同:
@Transactional(readOnly = true) public List<CarDtoNoSetters> fetchCarsNoSetters() { Query query = entityManager .createQuery("select c.name as name, c.color as color from Car c") .unwrap(org.hibernate.query.Query.class) .setResultTransformer( new AliasToBeanConstructorResultTransformer( CarDtoNoSetters.class.getConstructors()[0] ) ); List<CarDtoNoSetters> result = query.getResultList(); return result; } @Transactional(readOnly = true) public List<CarDtoWithSetters> fetchCarsWithSetters() { Query query = entityManager .createQuery("select c.name as name, c.color as color from Car c") .unwrap(org.hibernate.query.Query.class) .setResultTransformer( Transformers.aliasToBean(CarDtoWithSetters.class) );
List<CarDtoWithSetters> result = query.getResultList(); return result; }
|
原生SQL
JPQL源码