文章目录
- 命名查询
- 动态SQL
- 单表动态条件查询
- 多表动态条件查询
- JPA对SQL支持
- 删除数据(delete)(HQL)
- 修改数据(update)(HQL)
- 单表查询(HQL)
- 多表连接查询并支持分页(原生SQL)
- 自定义SQL和防SQL注入
- 动态SQL超级工具(推荐)
- 作者劝语
命名查询
关键字 | 方法命名 | sql where字句 |
And | findByNameAndPwd | where name= ? and pwd =? |
or | findByNameOrSex | where name= ? or sex=? |
Is,Equals | findById,findByIdEquals | where id= ? |
Between | findByIdBetween | where id between ? and ? |
LessThan | findByIdLessThan | where id < ? |
LessThanEquals | findByIdLessThanEquals | where id <= ? |
GreaterThan | findByIdGreaterThan | where id > ? |
GreaterThanEquals | findByIdGreaterThanEquals | where id > = ? |
After | findByIdAfter | where id > ? |
Before | findByIdBefore | where id < ? |
IsNull | findByNameIsNull | where name is null |
IsNotNull, NotNull | findByNameNotNull | where name is not null |
Like | findByNameLike | where name like ? |
NotLike | findByNameNotLike | where name not like ? |
StartingWith | findByNameStartingWith | where name like ‘?%’ |
EndingWith | findByNameEndingWith | where name like ‘%?’ |
Containing | findByNameContaining | where name like ‘%?%’ |
OrderBy | findByIdOrderByXDesc | where id=? order by x desc |
Not | findByNameNot | where name <> ? |
In | findByIdIn(Collection<?> c) | where id not in (?) |
NotIn | findByIdNotIn(Collection<?> c) | where id in (?) |
True | findByAaaTrue | here aaa = true |
False | findByAaaFalse | here aaa = false |
IgnoreCase | findByNameIgnoreCase | where UPPER(name)=UPPER(?) |
eg:
//查询第一条记录First
Account findFirstByOrderByCreateAtDesc();
//排序ASC DESC,以下分别按lastname升序,按age降序
User findFirstByOrderByChannelCodeAsc();
User findTopByOrderByChannelCodeDesc();
//带分页,Pageable为分页参数,实现类PageRequest,通过PageRequest.of(...)生成分页对象
Page queryFirst10ByVmCode(String vmCode, Pageable pageable);
Slice findTop3ByVmCode(String vmCode, Pageable pageable);
//带Sort排序,查询前10条
List findFirst10ByVmCode(String vmCode, Sort sort);
- Sort和Pageable放方法参数列表的最后
动态SQL
单表动态条件查询
- 前端传来N个字段,随机组合其中几个字段组成SQL进行查询
Page<Node> page;
Specification<Node> cation = (root, query, builder) -> {
List<Predicate> predicates = new ArrayList<>();
if (!StringUtils.isEmpty((nodeParam.getCompanyCode()))) {
predicates.add(builder.equal(root.get("companyCode"), nodeParam.getCompanyCode()));
}
if (!StringUtils.isEmpty(nodeParam.getNodeName())) {
predicates.add(builder.like(root.get("nodeName"), "%" + nodeParam.getNodeName() + "%"));
}
if (predicates.size() > 1) {
return builder.and(predicates.toArray(new Predicate[predicates.size()]));
} else if (predicates.size() == 1) {
return predicates.get(0);
} else {
return null;
}
};
page = nodeRepository.findAll(cation, nodeParam.getPageable());
多表动态条件查询
- 4张表动态SQL,前端传来N个字段,随机组合其中几个字段组成SQL进行查询
Specification<ErrorRender> cation = (root, criteriaQuery, builder) -> {
List<Predicate> predicates = new ArrayList<>();
predicates.add(builder.greaterThan(root.get("vmCode"), vmCode));
predicates.add(builder.equal(root.get("status"), 0).not());
//ErrorRender故障表和Vm表进行连接查询,在ErrorRender必须有一个private Vm vm属性
//相当于 select * from error_render e left join vm v on e.vm=v.vm
Join<ErrorRender, Vm> vmJoin = root.join("vm", JoinType.LEFT);
//机型条件 相当于 v.vmTypeId >= 0
if (vmTypeId >= 0) {
predicates.add(builder.equal(vmJoin.get("vmTypeId"), vtId));
}
// 相当于(left on node n on v.node_id=n.node_id) as tmp left join org o on o.org_id= tmp.org_id
Join<Vms, Orgas> orgJoin = vmJoin.join("node", JoinType.LEFT).join("org", JoinType.LEFT);
//带有orgId查询
Orgas org = orgasRepository.findOne(orgId);
//相当于 o.hierarchy like org.getHierarchy() + "%"
predicates.add(builder.like(orgJoin.get("hierarchy"), org.getHierarchy() + "%"));
if (error != null && error != 0) {
predicates.add(root.get("error").in(allErrorList));
}
if (predicates.size() > 1) {
return builder.and(predicates.toArray(new Predicate[predicates.size()]));
} else if (predicates.size() == 1) {
return predicates.get(0);
} else {
return null;
}
};
JPA对SQL支持
删除数据(delete)(HQL)
//删除需要添加@Modifying注解,@Transactional可加可不加,加上后,将以repository类中的事务为主
@Modifying
@Query("delete from VmModelUnitRelation v where v.vmModelId=?1")
void deleteByVmModelId(Long vmModelId);
//可在仓库类中定义SQL语句,在@Query中引用
String FIND_VM_MODELID = "delete from VmModelUnitRelation v where v.vmModelId=?1";
@Query(FIND_VM_MODELID) //FIND_VM_MODELID可继续添加查询条件
void deleteByVmModelId(Long vmModelId);
修改数据(update)(HQL)
//更新需要添加@Modifying注解 命名参数绑定,对参数顺序要求不严格
@Modifying
@Query(value = "update Vm v set v.deviceCode = :deviceCode where c.id = :vmCode")
public void updateDeviceCode(@Param("vmCode") String vmCode, String deviceCode);
@Modifying
@Query(value = "update Vm v set v.deviceCode = ?2 where c.id = ?1")
public void updateDeviceCode(String vmCode, String deviceCode);
单表查询(HQL)
@Query("select v from Vm v where v.vmCode = ?1 and channelCode = ?2")
User findByVmCodeAndChannelCode(String vmCode, Integer channelCode)
//分页
@Query("select v from Vm v where v.vmCode = ?1 and channelCode = ?2")
User findByVmCodeAndChannelCode(String vmCode, Integer channelCode, Pageable pageable)
多表连接查询并支持分页(原生SQL)
- 只需要设置nativeQuery为true
@Query(value = "SELECT vm.* FROM vm AS vm LEFT JOIN vm_auailiary AS auailiary ON vm.vm_code != auailiary.vm_code WHERE vm.node_id=:nodeId AND vm.host_type=:hostType",
countQuery = "SELECT count(vm.vm_code) FROM vm AS vm LEFT JOIN vm_auailiary AS auailiary ON vm.vm_code != auailiary.vm_code WHERE vm.node_id=:nodeId AND vm.host_type=:hostType",
nativeQuery = true)
Page<Vm> findByNodeIdAndVmCodeNotIn(@Param("nodeId") String nodeId, @Param("hostType")Integer hostType, Pageable pageable);
自定义SQL和防SQL注入
- 使用原生SQL
@Service
public class JdbcTemplateService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private NamedParameterJdbcTemplate nameJdbcTemplate;
/**
* 防止SQL注入(适用于参数占位符为 ? 的参数语句,如果参数为命名绑定,则使用Map设置参数)
* @param sql sql语句
* @param params 按 ? 顺序添加参数
* @param clazz 返回List包含对象class
*/
public <T> List<T> queryList(String sql, @Nullable Object[] params, Class<T> clazz){
return jdbcTemplate.queryForList(sql, params, clazz);
}
/**
* 防止SQL注入,适用于参数为命名绑定形式(如 vmCode = :vmCode) (推荐)
* @param sql sql语句
* @param paramMap 参数Map,key为绑定的命名参数(:后面的名称,如上为vmCode)
* @param clazz 返回List包含对象class
*/
public <T> List<T> queryList(String sql, Map<String, Object> paramMap, Class<T> clazz){
if(paramMap == null){
paramMap = new HashMap<>();
}
return nameJdbcTemplate.query(sql, paramMap, new BeanPropertyRowMapper<>(clazz));
}
/**
* 查询单个对象
* @param sql sql语句
* @param clazz 对象class
*/
public <T> T queryOne(String sql, Class<T> clazz){
return jdbcTemplate.queryForObject(sql, clazz);
}
/**
* @param sql sql语句
* @return List列表中是一个个返回对象,Map的key为字段名,value为对应字段值
*/
public List<Map<String, Object>> queryList(String sql){
return jdbcTemplate.queryForList(sql);
}
/**
* 查询指定返回对象类型列表(不能防止SQL注入)
* @param sql sql语句
* @param clazz 返回List包含对象class
*/
public <T> List<T> queryList(String sql, Class<T> clazz){
return jdbcTemplate.queryForList(sql, clazz);
}
}
动态SQL超级工具(推荐)
【JPA-SPEC】https://github.com/wenhao/jpa-spec/blob/master/README_CN.md
作者劝语
- 请务必先使用JPA命名查询
- 命名查询无法解决请使用JPA的动态SQL
- 多表联合查询在对性能有较大提升的情况下,可使用JPA的@Query
- 在动态SQL和JPA的@Query均不好解决的情况下,方可使用jdbc(务必使用防SQL注入方法)