Java >> Java tutorial >  >> Tag >> mybatis

Hvordan bruger man annoteringer med iBatis (myBatis) til en IN-forespørgsel?

Jeg tror, ​​at svaret er det samme, som er givet i dette spørgsmål. Du kan bruge myBatis Dynamic SQL i dine annoteringer ved at gøre følgende:

@Select({"<script>",
 "SELECT *", 
 "FROM blog",
 "WHERE id IN", 
 "<foreach item='item' index='index' collection='list'",
 "open='(' separator=',' close=')'>",
 "#{item}",
 "</foreach>",
 "</script>"}) 
List<Blog> selectBlogs(@Param("list") int[] ids);

<script> element muliggør dynamisk SQL-parsing og udførelse af annoteringen. Det skal være det allerførste indhold i forespørgselsstrengen. Intet må være foran det, ikke engang hvidt mellemrum.

Bemærk, at de variabler, som du kan bruge i de forskellige XML-script-tags, følger de samme navnekonventioner som almindelige forespørgsler, så hvis du vil henvise til dine metodeargumenter ved at bruge andre navne end "param1", "param2", osv... skal præfiksere hvert argument med en @Param-annotation.


Jeg mener, at dette er en nuance af jdbc's udarbejdede udtalelser og ikke MyBatis. Der er et link her, der forklarer dette problem og tilbyder forskellige løsninger. Desværre er ingen af ​​disse løsninger levedygtige for din ansøgning, men det er stadig en god læsning for at forstå begrænsningerne af forberedte erklæringer med hensyn til en "IN"-klausul. En løsning (måske suboptimal) kan findes på den DB-specifikke side af tingene. For eksempel, i postgresql, kunne man bruge:

"SELECT * FROM blog WHERE id=ANY(#{blogIds}::int[])"

"ANY" er det samme som "IN" og "::int[]" er typen, der kaster argumentet ind i en matrix af ints. Argumentet, der føres ind i erklæringen, skal se nogenlunde sådan ud:

"{1,2,3,4}"

Havde nogle undersøgelser om dette emne.

  1. en af ​​de officielle løsninger fra mybatis er at sætte din dynamiske sql i @Select("<script>...</script>") . Men at skrive xml i java-annotering er ret ungaciøst. tænk over denne @Select("<script>select name from sometable where id in <foreach collection=\"items\" item=\"item\" seperator=\",\" open=\"(\" close=\")\">${item}</script>")
  2. @SelectProvider fungerer fint. Men det er lidt kompliceret at læse.
  3. PreparedStatement tillader ikke, at du angiver en liste over heltal. pstm.setString(index, "1,2,3,4") vil lade din SQL som denne select name from sometable where id in ('1,2,3,4') . Mysql vil konvertere tegn '1,2,3,4' til nummer 1 .
  4. FIND_IN_SET virker ikke med mysql index.

Kig ind i mybatis dynamiske sql-mekanisme, den er blevet implementeret af SqlNode.apply(DynamicContext) . Dog @Vælg uden <script></script> annotering vil ikke sende parameter via DynamicContext

se også

  • org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
  • org.apache.ibatis.scripting.xmltags.DynamicSqlSource
  • org.apache.ibatis.scripting.xmltags.RawSqlSource

Så,

  • Løsning 1:Brug @SelectProvider
  • Løsning 2:Udvid LanguageDriver, som altid vil kompilere sql til DynamicSqlSource . Du skal dog stadig skrive \" overalt.
  • Løsning 3:Udvid LanguageDriver, som kan konvertere din egen grammatik til mybatis one.
  • Løsning 4:Skriv din egen LanguageDriver, som kompilerer SQL med en eller anden skabelonrenderer, ligesom mybatis-velocity project gør. På denne måde kan du endda integrere groovy.

Mit projekt tager løsning 3 og her er koden:

public class MybatisExtendedLanguageDriver extends XMLLanguageDriver 
 implements LanguageDriver {
 private final Pattern inPattern = Pattern.compile("\\(#\\{(\\w+)\\}\\)");
 public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {
 Matcher matcher = inPattern.matcher(script);
 if (matcher.find()) {
 script = matcher.replaceAll("(<foreach collection=\"$1\" item=\"__item\" separator=\",\" >#{__item}</foreach>)");
 }
 script = "<script>" + script + "</script>";
 return super.createSqlSource(configuration, script, parameterType);
 }
}

Og brugen:

@Lang(MybatisExtendedLanguageDriver.class)
@Select("SELECT " + COLUMNS + " FROM sometable where id IN (#{ids})")
List<SomeItem> loadByIds(@Param("ids") List<Integer> ids);

Java tag