日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

@param注解_启用 parameters 编译选项简化 mybatis @Param 注解重复问题

發布時間:2025/3/19 编程问答 65 豆豆
生活随笔 收集整理的這篇文章主要介紹了 @param注解_启用 parameters 编译选项简化 mybatis @Param 注解重复问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在使用 mybatis 查詢的時候, 只需要定義一個查詢接口, mybatis 會為我們注入注解實現或是 xml 實現. 但當我們需要傳遞參數時, 通常需要 @Param 來定義一個名稱, 但經常的, 我們也不難發現, 這個名稱與參數名稱通常是一樣的:

User findUser(@Param("username") String username, @Param("password") String password);

如上, username 和 password 都重復了.

而之所以要這么使用, 是因為 xml 中 ${xxx} 所引用的名稱就來自于 @Param 里定義的值:

<select id="findUser" resultType="net.xiaogd.demo.mybatis.entity.User">
select * from user where username = #{username} and password = #{password}
select>

這就帶來一個重復的問題, 可否簡化這個定義, 使得無需重復錄入名稱, 甚至完全地去掉呢? 比如像下面這樣:

User findUser(String username, String password);

答案是可以的, 下面就來說下怎么去做到這一點.

前置條件

  • 首先項目需要使用 jdk8 或以上;

  • 其次, 需要增加一個編譯時的選項?-parameters.

    也即是這樣去編譯:?javac -parameters

  • 通常, 如果沒有加上這個選項, 編譯后的方法參數簽名會變成這樣:

    User findUser(String arg0, String arg1);

    實際的名稱會變成如上所示的?arg0,?arg1?這樣沒有太多含義的, 畢竟解析器并不關心實際的名稱, 有含義的名稱只是給人閱讀的而已.

    下面就說說怎么去引入這個編譯選項以使得可以保留有意義的參數名, 包括 maven 中的設置及 IDE 中的設置(包括 Intellij IDEA 和 Eclipse)

    maven 編譯時的選項

    對于 maven, 可以在編譯插件 maven-compiler-plugin 中使用 compilerArgs 增加參數來實現:

    <plugin>
    <groupId>org.apache.maven.pluginsgroupId>
    <artifactId>maven-compiler-pluginartifactId>
    <configuration>
    <compilerArgs>
    <arg>-parametersarg>
    compilerArgs>
    configuration>
    plugin>

    注: 對于較新的 maven 版本(>= 3.6.2), 也可以直接使用 parameters 配置項:

    <plugin>
    <groupId>org.apache.maven.pluginsgroupId>
    <artifactId>maven-compiler-pluginartifactId>
    <configuration>
    <parameters>trueparameters>
    configuration>
    plugin>

    參見:?https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#parameters

    另注: 如果你使用 spring boot 2.0 及以后的版本并依賴了 spring-boot-starter-parent, 默認情況下已經啟用了這一選項:

    參見這里的說明:?https://stackoverflow.com/questions/31845676/how-to-compile-spring-boot-applications-with-java-8-parameter-flag/49316086#49316086

    你可以通過查看最終生效的 Effective POM 來確認這一點, 對于 Eclipse, 在打開的 pom.xml 文件下方選項卡中選擇"Effective POM", 然后搜索 maven-compiler-plugin 關鍵字可以找到相關配置:?

    對于 Intellij IDEA, 在 maven 窗口中 右鍵--Show Effective POM:?

    或者通過實際是否正常運行來確認這一點, 如果不是很確定, 當然你可以如上所述在自己的 pom.xml 文件中顯式地配置上它.

    IDE 編譯時保留參數名稱

    說完了 maven 中的配置, 下面再說說在 IDE 中的類似設置.

    注: 通常, 如果 maven 中設置了相應選項, 在項目作為 maven 項目導入并構建時, 這些額外的設置也會生效, 無需額外再作設置. 但考慮到 IDE 的版本及可能存在 bug 等各類原因, 如果在 IDE 中運行不正常, 那么則需要額外檢查及配置.

    Intellij IDEA 中的設置 -parameters

    對于 IDEA, 在下述位置 Settings > Build, Execution, Deployment > Compiler > Java Compiler > Additional command line parameters(額外的命令行參數) 的輸入框中, 輸入-parameters:

    參考:?https://stackoverflow.com/questions/39217830/how-to-use-parameters-javac-option-in-intellij

    如前所述, 如果沒有設置也運行正常, 則不必去設置.

    Eclipse 中的設置 -parameters

    對于 Eclipse, 則是檢查 Store information about method parameters 選項, 看看是否已經是勾選上, 如果沒有, 則把它勾上:

    如前所述, 如果沒有勾選也運行正常或者默認已經勾選上了, 則不必再去勾選.

    另注: 因為以上設置涉及編譯, 所以通常需要重新編譯項目(如果設置后沒有自動觸發 rebuild), 如果還不生效, 甚至可能需要重啟 IDE.

    沒有配置成功時的異常

    如果沒有加入 -parameters 選項或因其它原因沒有啟用成功, 則去掉 @Param 注解后可能會遇到下述異常:

    exception: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'username' not found. Available parameters are [arg1, arg0, param1, param2]

    完整的異常如下:

    exception:
    org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'username' not found. Available parameters are [arg1, arg0, param1, param2]
    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
    at com.sun.proxy.$Proxy78.selectList(Unknown Source)
    at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:230)
    at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:137)
    at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:75)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
    at com.sun.proxy.$Proxy86.findUserByUsernameAndPassword(Unknown Source)
    at net.xiaogd.demo.mybatis.dao.user.UserDaoTest.testXmlDao(UserDaoTest.java:76)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
    Caused by: org.apache.ibatis.binding.BindingException: Parameter 'username' not found. Available parameters are [arg1, arg0, param1, param2]
    at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:202)
    at org.apache.ibatis.reflection.wrapper.MapWrapper.get(MapWrapper.java:45)
    at org.apache.ibatis.reflection.MetaObject.getValue(MetaObject.java:122)
    at org.apache.ibatis.executor.BaseExecutor.createCacheKey(BaseExecutor.java:219)
    at org.apache.ibatis.executor.CachingExecutor.createCacheKey(CachingExecutor.java:146)
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:82)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433)
    ... 38 more

    那么, 按照其提示, 可以將相應的 xml 語句調整為:

    <select id="findUser" resultType="net.xiaogd.demo.mybatis.entity.User">
    select * from user where username = #{arg0} and password = #{arg1}
    select>

    或者是使用 param1, param2 這樣的名稱(注意, 與 arg 從 0 編號不同, 這里是從 1 開始編號)

    <select id="findUser" resultType="net.xiaogd.demo.mybatis.entity.User">
    select * from user where username = #{param1} and password = #{param2}
    select>

    自然, 使用這些沒有太多含義的編號參數名, 代碼的可讀性就差了很多, 參數是否正確對上了也不容易看出來.

    mybatis 版本及 useActualParamName(use-actual-param-name) 的問題

    最后, 還有一個配置 useActualParamName(使用實際的參數名稱) 可能導致一些異常, 這點與 mybatis 不同版本的缺省配置不同有關, 也與項目本身是否顯式配置了這一參數值有關.

    在沒有啟用 -parameters 以保留方法參數名并且沒有用 @Param 設置一個有效的名稱時, 有時你可能會發現使用 arg0 也還是提示找不到參數:

    org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'arg0' not found. Available parameters are [0, 1, param1, param2]

    完整的異常如下:

    org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'arg0' not found. Available parameters are [0, 1, param1, param2]
    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446)
    at com.sun.proxy.$Proxy78.selectList(Unknown Source)
    at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:230)
    at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:137)
    at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:75)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
    at com.sun.proxy.$Proxy86.findUserByUsernameAndPassword(Unknown Source)
    at net.xiaogd.demo.mybatis.dao.user.UserDaoTest.testXmlDao(UserDaoTest.java:76)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
    Caused by: org.apache.ibatis.binding.BindingException: Parameter 'arg0' not found. Available parameters are [0, 1, param1, param2]
    at org.apache.ibatis.binding.MapperMethod$ParamMap.get(MapperMethod.java:202)
    at org.apache.ibatis.reflection.wrapper.MapWrapper.get(MapWrapper.java:45)
    at org.apache.ibatis.reflection.MetaObject.getValue(MetaObject.java:122)
    at org.apache.ibatis.executor.BaseExecutor.createCacheKey(BaseExecutor.java:219)
    at org.apache.ibatis.executor.CachingExecutor.createCacheKey(CachingExecutor.java:146)
    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:82)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:148)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433)
    ... 38 more

    而這是由于 mybatis 版本及 useActualParamName(use-actual-param-name) 選項設置的原因.

    在早期的版本中(< 3.4.1), useActualParamName 選項的默認值是 false, 而之后的版本(>= 3.4.1), 這個選項的默認值則是 true.

    只有設置為 true, 才能利用 -parameters 配置帶來的好處.

    或者就是項目本身配置了其它不同于缺省的值, 如果使用了 spring boot 項目, 可以檢查如下選項:

    mybatis.configuration.use-actual-param-name=false

    或是在 xml 配置文件中設置:

    <setting name="useActualParamName" value="false" />

    如果設置了 false, 那么就要寫成 #{0}, #{1} 這樣:

    <select id="findUser" resultType="net.xiaogd.demo.mybatis.entity.User">
    select * from user where username = #{0} and password = #{1}
    select>

    如果以前有大量這樣的寫法, 而你為了兼容它們不想去調整, 那你就無法利用 -parameters 配置帶來的好處.

    無論是使用 {0}, {1}, 還是使用 {arg0}, {arg1}, 可讀性都不是很好, 而且在后續如果需要增加參數, 還容易引入錯誤, 因此并不推薦這樣的寫法.

    關于啟用 -parameters 編譯選項簡化 mybatis @Param 注解重復問題就介紹到這里.

    總結

    以上是生活随笔為你收集整理的@param注解_启用 parameters 编译选项简化 mybatis @Param 注解重复问题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。