在 SQL 查询中使用 'true' 而不是 true 会产生意想不到的结果
Using 'true' as opposed to true in an SQL query gives unexpected results
当 运行ning jpql 使用 entityManager 对象查询时,我发现了一些奇怪的东西。
我获取任何对象的 ID 号,其布尔字段对于列名 plantClimbs
frostresistant
或 spicy
为真
当 plantClimbs 为 true 时,我创建的方法生成如下所示的查询字符串
select u.id from SeedRecord u WHERE u.climbingPlant = 'true'
当我 运行 这个查询时,我看到了一些意想不到的结果。它不是检索所有 climbingPlant 字段为 true 的 SeedRecord id,而是获取 climbingPlant 字段为 false 且 frostResistant 或 Spicy 字段恰好为 true 的种子记录的所有 id。
当我删除 true 周围的 ' 字符时,它又开始获取正确的 ID。我的问题是:为什么会这样?为什么将 ' 放在 true 周围似乎否定了所有内容,以至于实际上获取了 climbingPLant 字段为 false 的 seedrecords?
这是我的完整方法:
private Set<Long> findAllSeedRecordsByKeywordsOrBooleans(Set<String> checkKeywords, boolean plantClimbs, boolean teaPlant, boolean spicy){
if (checkKeywords.isEmpty()
&& !plantClimbs
&& !spicy
&& !teaPlant) return Collections.EMPTY_SET;
Set<String> availablePlantTypes = new HashSet<>();
Set<String> availableProduceTypes = new HashSet<>();
log.info("fetching entitymanager");
EntityManager entityManager = seedRecordDao.getEntityManager();
Map<String,Set<String>> containsProduceNameKeyword = new HashMap<>();
Map<String,Set<PlantType>> containsPlantTypeKeyword = new HashMap<>();
Map<String,Set<ProduceType>> containsProduceTypeKeyword = new HashMap<>();
Set<String> searchProduceNames = new HashSet<>();
Set<PlantType> searchPlantTypes = new HashSet<>();
Set<ProduceType> searchProduceTypes = new HashSet<>();
boolean hasPriorCondition = false;
boolean produceNamesConditionApplied = false;
boolean produceTypesConditionApplied = false;
boolean plantTypesConditionApplied = false;
StringBuilder filterQuery = new StringBuilder("select u.id from SeedRecord u WHERE ");
if(!checkKeywords.isEmpty()) {
log.info("getting the producenames");
Set<String> availableProduceNames = seedRecordDao.getProduceNames()
.stream().map(ProduceName::getProduceName).collect(Collectors.toSet());
for (PlantType plantType : PlantType.values())
availablePlantTypes.add(plantType.toString());
for (ProduceType produceType : ProduceType.values())
availableProduceTypes.add(produceType.toString());
for (String keyword : checkKeywords) {
if (availableProduceNames.contains(keyword)) {
searchProduceNames.add(keyword);
if (!produceNamesConditionApplied) {
if (!hasPriorCondition) {
filterQuery.append("u.produceName IN :produceNames ");
hasPriorCondition = true;
} else
filterQuery.append("OR u.produceName IN :produceNames ");
produceNamesConditionApplied = true;
}
} else if (availablePlantTypes.contains(keyword)) {
searchPlantTypes.add(PlantType.valueOf(keyword));
if (!plantTypesConditionApplied) {
if (!hasPriorCondition) {
filterQuery.append("u.plantType IN :plantTypes ");
hasPriorCondition = true;
} else
filterQuery.append("OR u.plantType IN :plantTypes ");
plantTypesConditionApplied = true;
}
} else if (availableProduceTypes.contains(keyword)) {
searchProduceTypes.add(ProduceType.valueOf(keyword));
if (!produceTypesConditionApplied) {
if (!hasPriorCondition) {
filterQuery.append("u.produceType IN :produceTypes ");
hasPriorCondition = true;
} else
filterQuery.append("OR u.produceType IN :produceTypes ");
produceTypesConditionApplied = true;
}
}
}
if (!searchProduceNames.isEmpty())
containsProduceNameKeyword.put("produceNames", searchProduceNames);
if (!searchProduceTypes.isEmpty())
containsProduceTypeKeyword.put("produceTypes", searchProduceTypes);
if (!searchPlantTypes.isEmpty())
containsPlantTypeKeyword.put("plantTypes", searchPlantTypes);
}
if(plantClimbs)
if (!hasPriorCondition) {
filterQuery.append("u.climbingPlant = 'true' ");
hasPriorCondition = true;
}
else
filterQuery.append("OR u.climbingPlant = 'true' ");
if(teaPlant)
if (!hasPriorCondition) {
filterQuery.append("u.teaPlant = 'true' ");
hasPriorCondition = true;
}
else
filterQuery.append("OR u.teaPlant = 'true' ");
if(spicy)
if (!hasPriorCondition) {
filterQuery.append("u.spicy = 'true' ");
}
else
filterQuery.append("OR u.spicy = 'true' ");
try {
log.info("preparing query");
log.info(filterQuery.toString());
TypedQuery<Long> query = entityManager.createQuery(filterQuery.toString(), Long.class);
if (!containsProduceNameKeyword.isEmpty())
containsProduceNameKeyword.forEach((parameter, input) -> query.setParameter(parameter, input));
if (!containsPlantTypeKeyword.isEmpty())
containsPlantTypeKeyword.forEach((parameter, input) -> query.setParameter(parameter, input));
if (!containsProduceTypeKeyword.isEmpty())
containsProduceTypeKeyword.forEach((parameter, input) -> query.setParameter(parameter, input));
log.info("sending to database NOW");
return new HashSet<>(query.getResultList());
}
catch(Exception e){
throw e;
}
}
这是因为您的 climbingPlant
列是布尔值,所以 MySQL 必须将 'true'
转换为布尔值才能与其进行比较,这是(并且对于任何字符串)错误。因此,当您在引号中包含 true
时,当 climbingPlant
为假时,它匹配 climbingPlant
。其他列的值无关紧要。如需演示,请尝试以下操作:
select 'true' = true, 'true' = false, 'anything' = false
输出:
'true' = true 'true' = false 'anything' = false
0 1 1
当 运行ning jpql 使用 entityManager 对象查询时,我发现了一些奇怪的东西。
我获取任何对象的 ID 号,其布尔字段对于列名 plantClimbs
frostresistant
或 spicy
当 plantClimbs 为 true 时,我创建的方法生成如下所示的查询字符串
select u.id from SeedRecord u WHERE u.climbingPlant = 'true'
当我 运行 这个查询时,我看到了一些意想不到的结果。它不是检索所有 climbingPlant 字段为 true 的 SeedRecord id,而是获取 climbingPlant 字段为 false 且 frostResistant 或 Spicy 字段恰好为 true 的种子记录的所有 id。
当我删除 true 周围的 ' 字符时,它又开始获取正确的 ID。我的问题是:为什么会这样?为什么将 ' 放在 true 周围似乎否定了所有内容,以至于实际上获取了 climbingPLant 字段为 false 的 seedrecords?
这是我的完整方法:
private Set<Long> findAllSeedRecordsByKeywordsOrBooleans(Set<String> checkKeywords, boolean plantClimbs, boolean teaPlant, boolean spicy){
if (checkKeywords.isEmpty()
&& !plantClimbs
&& !spicy
&& !teaPlant) return Collections.EMPTY_SET;
Set<String> availablePlantTypes = new HashSet<>();
Set<String> availableProduceTypes = new HashSet<>();
log.info("fetching entitymanager");
EntityManager entityManager = seedRecordDao.getEntityManager();
Map<String,Set<String>> containsProduceNameKeyword = new HashMap<>();
Map<String,Set<PlantType>> containsPlantTypeKeyword = new HashMap<>();
Map<String,Set<ProduceType>> containsProduceTypeKeyword = new HashMap<>();
Set<String> searchProduceNames = new HashSet<>();
Set<PlantType> searchPlantTypes = new HashSet<>();
Set<ProduceType> searchProduceTypes = new HashSet<>();
boolean hasPriorCondition = false;
boolean produceNamesConditionApplied = false;
boolean produceTypesConditionApplied = false;
boolean plantTypesConditionApplied = false;
StringBuilder filterQuery = new StringBuilder("select u.id from SeedRecord u WHERE ");
if(!checkKeywords.isEmpty()) {
log.info("getting the producenames");
Set<String> availableProduceNames = seedRecordDao.getProduceNames()
.stream().map(ProduceName::getProduceName).collect(Collectors.toSet());
for (PlantType plantType : PlantType.values())
availablePlantTypes.add(plantType.toString());
for (ProduceType produceType : ProduceType.values())
availableProduceTypes.add(produceType.toString());
for (String keyword : checkKeywords) {
if (availableProduceNames.contains(keyword)) {
searchProduceNames.add(keyword);
if (!produceNamesConditionApplied) {
if (!hasPriorCondition) {
filterQuery.append("u.produceName IN :produceNames ");
hasPriorCondition = true;
} else
filterQuery.append("OR u.produceName IN :produceNames ");
produceNamesConditionApplied = true;
}
} else if (availablePlantTypes.contains(keyword)) {
searchPlantTypes.add(PlantType.valueOf(keyword));
if (!plantTypesConditionApplied) {
if (!hasPriorCondition) {
filterQuery.append("u.plantType IN :plantTypes ");
hasPriorCondition = true;
} else
filterQuery.append("OR u.plantType IN :plantTypes ");
plantTypesConditionApplied = true;
}
} else if (availableProduceTypes.contains(keyword)) {
searchProduceTypes.add(ProduceType.valueOf(keyword));
if (!produceTypesConditionApplied) {
if (!hasPriorCondition) {
filterQuery.append("u.produceType IN :produceTypes ");
hasPriorCondition = true;
} else
filterQuery.append("OR u.produceType IN :produceTypes ");
produceTypesConditionApplied = true;
}
}
}
if (!searchProduceNames.isEmpty())
containsProduceNameKeyword.put("produceNames", searchProduceNames);
if (!searchProduceTypes.isEmpty())
containsProduceTypeKeyword.put("produceTypes", searchProduceTypes);
if (!searchPlantTypes.isEmpty())
containsPlantTypeKeyword.put("plantTypes", searchPlantTypes);
}
if(plantClimbs)
if (!hasPriorCondition) {
filterQuery.append("u.climbingPlant = 'true' ");
hasPriorCondition = true;
}
else
filterQuery.append("OR u.climbingPlant = 'true' ");
if(teaPlant)
if (!hasPriorCondition) {
filterQuery.append("u.teaPlant = 'true' ");
hasPriorCondition = true;
}
else
filterQuery.append("OR u.teaPlant = 'true' ");
if(spicy)
if (!hasPriorCondition) {
filterQuery.append("u.spicy = 'true' ");
}
else
filterQuery.append("OR u.spicy = 'true' ");
try {
log.info("preparing query");
log.info(filterQuery.toString());
TypedQuery<Long> query = entityManager.createQuery(filterQuery.toString(), Long.class);
if (!containsProduceNameKeyword.isEmpty())
containsProduceNameKeyword.forEach((parameter, input) -> query.setParameter(parameter, input));
if (!containsPlantTypeKeyword.isEmpty())
containsPlantTypeKeyword.forEach((parameter, input) -> query.setParameter(parameter, input));
if (!containsProduceTypeKeyword.isEmpty())
containsProduceTypeKeyword.forEach((parameter, input) -> query.setParameter(parameter, input));
log.info("sending to database NOW");
return new HashSet<>(query.getResultList());
}
catch(Exception e){
throw e;
}
}
这是因为您的 climbingPlant
列是布尔值,所以 MySQL 必须将 'true'
转换为布尔值才能与其进行比较,这是(并且对于任何字符串)错误。因此,当您在引号中包含 true
时,当 climbingPlant
为假时,它匹配 climbingPlant
。其他列的值无关紧要。如需演示,请尝试以下操作:
select 'true' = true, 'true' = false, 'anything' = false
输出:
'true' = true 'true' = false 'anything' = false
0 1 1