文档引用:http://www.mybatis.cn/archives/678.html
视频参考:https://www.bilibili.com/video/BV1NE411Q7Nx?p=15
注解与xml取舍
在没有注解之前,xml被广泛的应用于描述元数据,xml的维护越来越糟糕。
在需要紧耦合的地方,比xml该容易维护,阅读更方便。
在需要比较多参数设置时,使用xml更方便,而在将某个方法声明为服务时这种紧耦合的情况下,
比较适合注解。
xml是松耦合的,注解是紧耦合的,对于xml和注解的使用,要具体问题具体分析。
例如,这种情况下xml更胜一筹:MyBatis XML配置对抗MyBatis注解的一大杀器:SQL片段,抽取可重用的SQL语句
java的注解没有行为,只能有数据,实际上就是一组键值对而已。
通过解析类(Parse Class)就能把一个注解设置的键值对都找出来。
mybatis 注解与xml配置
因为最初设计时,MyBatis是一个XML驱动的框架。
配置信息是基于XML的,而且映射语句也是定义在XML中的。
而到了MyBatis3,有新的选择了:利用注解实现SQL的映射。
MyBatis3构建在全面而且强大的Java 注解(Java annotation)之上。
注解提供了一种便捷的方式来实现简单SQL映射语句,可以简化编写XML的过程。
MyBatis基于注解的用法,正在变得越来越流行,
但是需要注意的是:注解的方式还没有百分百覆盖所有XML标签,所以还是有一点点不足!
快速入门
新建一个CRUD的Mapper接口
public interface UserAnnotationMapper { @Select("SELECT * FROM `user`;") List<User> getAllUserList(); }
我们不需要再写Mapper接口配置了
直接再核心配置中注册接口即可
测试发生了错误
java.lang.ExceptionInInitializerError at SqlSessionTest.sqlTest(SqlSessionTest.java:124) 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:59) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63) at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.junit.runners.ParentRunner.run(ParentRunner.java:413) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58) Caused by: org.apache.ibatis.exceptions.PersistenceException: ### Error building SqlSession. ### The error may exist in cn/dai/mapper/UserAnnotationMapper.java (best guess) ### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.binding.BindingException: Type interface cn.dai.mapper.UserAnnotationMapper is already known to the MapperRegistry. at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30) at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:80) at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:64) at cn.dai.util.MybatisUtil.<clinit>(MybatisUtil.java:26) ... 26 more Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.binding.BindingException: Type interface cn.dai.mapper.UserAnnotationMapper is already known to the MapperRegistry. at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:121) at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:98) at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:78) ... 28 more Caused by: org.apache.ibatis.binding.BindingException: Type interface cn.dai.mapper.UserAnnotationMapper is already known to the MapperRegistry. at org.apache.ibatis.binding.MapperRegistry.addMapper(MapperRegistry.java:63) at org.apache.ibatis.binding.MapperRegistry.addMappers(MapperRegistry.java:97) at org.apache.ibatis.binding.MapperRegistry.addMappers(MapperRegistry.java:105) at org.apache.ibatis.session.Configuration.addMappers(Configuration.java:771) at org.apache.ibatis.builder.xml.XMLConfigBuilder.mapperElement(XMLConfigBuilder.java:365) at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:119) ... 30 more
经过检查发现使用接口注册就不能和包扫描同时使用
<mappers> <mapper class="cn.dai.mapper.UserAnnotationMapper" /> <!--<package name="cn.dai.mapper"/>--> </mappers>
再测试就可行
[SqlSessionTest]-- - - - TESTING - - - - [org.apache.ibatis.logging.LogFactory]-Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter. [org.apache.ibatis.logging.LogFactory]-Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter. [org.apache.ibatis.io.VFS]-Class not found: org.jboss.vfs.VFS [org.apache.ibatis.io.JBoss6VFS]-JBoss 6 VFS API is not available in this environment. [org.apache.ibatis.io.VFS]-Class not found: org.jboss.vfs.VirtualFile [org.apache.ibatis.io.VFS]-VFS implementation org.apache.ibatis.io.JBoss6VFS is not valid in this environment. [org.apache.ibatis.io.VFS]-Using VFS adapter org.apache.ibatis.io.DefaultVFS [org.apache.ibatis.io.DefaultVFS]-Find JAR URL: file:/C:/Users/Administrator/IdeaProjects/Mybatis/Mybatis02%20-%20Configure/target/classes/cn/dai/pojo [org.apache.ibatis.io.DefaultVFS]-Not a JAR: file:/C:/Users/Administrator/IdeaProjects/Mybatis/Mybatis02%20-%20Configure/target/classes/cn/dai/pojo [org.apache.ibatis.io.DefaultVFS]-Reader entry: LimitSqlParam.class [org.apache.ibatis.io.DefaultVFS]-Reader entry: User.class [org.apache.ibatis.io.DefaultVFS]-Listing file:/C:/Users/Administrator/IdeaProjects/Mybatis/Mybatis02%20-%20Configure/target/classes/cn/dai/pojo [org.apache.ibatis.io.DefaultVFS]-Find JAR URL: file:/C:/Users/Administrator/IdeaProjects/Mybatis/Mybatis02%20-%20Configure/target/classes/cn/dai/pojo/LimitSqlParam.class [org.apache.ibatis.io.DefaultVFS]-Not a JAR: file:/C:/Users/Administrator/IdeaProjects/Mybatis/Mybatis02%20-%20Configure/target/classes/cn/dai/pojo/LimitSqlParam.class [org.apache.ibatis.io.DefaultVFS]-Reader entry: ���� 1 Q = > ? [org.apache.ibatis.io.DefaultVFS]-Find JAR URL: file:/C:/Users/Administrator/IdeaProjects/Mybatis/Mybatis02%20-%20Configure/target/classes/cn/dai/pojo/User.class [org.apache.ibatis.io.DefaultVFS]-Not a JAR: file:/C:/Users/Administrator/IdeaProjects/Mybatis/Mybatis02%20-%20Configure/target/classes/cn/dai/pojo/User.class [org.apache.ibatis.io.DefaultVFS]-Reader entry: ���� 1 _ H I J K [org.apache.ibatis.io.ResolverUtil]-Checking to see if class cn.dai.pojo.LimitSqlParam matches criteria [is assignable to Object] [org.apache.ibatis.io.ResolverUtil]-Checking to see if class cn.dai.pojo.User matches criteria [is assignable to Object] [org.apache.ibatis.datasource.pooled.PooledDataSource]-PooledDataSource forcefully closed/removed all connections. [org.apache.ibatis.datasource.pooled.PooledDataSource]-PooledDataSource forcefully closed/removed all connections. [org.apache.ibatis.datasource.pooled.PooledDataSource]-PooledDataSource forcefully closed/removed all connections. [org.apache.ibatis.datasource.pooled.PooledDataSource]-PooledDataSource forcefully closed/removed all connections. [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Opening JDBC Connection [org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 1536471117. [cn.dai.mapper.UserAnnotationMapper.getAllUserList]-==> Preparing: SELECT * FROM `user`; [cn.dai.mapper.UserAnnotationMapper.getAllUserList]-==> Parameters: [cn.dai.mapper.UserAnnotationMapper.getAllUserList]-<== Total: 16 User(user_id=1, user_name=杰哥, user_password=123456) User(user_id=2, user_name=阿伟, user_password=123456) User(user_id=3, user_name=空条承太郎, user_password=123456) User(user_id=4, user_name=乔鲁诺乔巴纳, user_password=123456) User(user_id=5, user_name=迪奥布兰多, user_password=123456) User(user_id=6, user_name=乔瑟夫乔斯达, user_password=123456) User(user_id=7, user_name=乔纳森乔斯达, user_password=123456) User(user_id=8, user_name=丽萨丽萨, user_password=654321) User(user_id=9, user_name=东方仗助, user_password=654321) User(user_id=10, user_name=东方定助, user_password=654321) User(user_id=11, user_name=花京院典明, user_password=654321) User(user_id=12, user_name=波鲁纳雷夫, user_password=654321) User(user_id=13, user_name=吉良吉影, user_password=654321) User(user_id=14, user_name=布加拉提, user_password=654321) User(user_id=15, user_name=葛德米斯达, user_password=131313) User(user_id=18, user_name=哈吉咩, user_password=335577) [org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@5b94b04d] [org.apache.ibatis.datasource.pooled.PooledDataSource]-Returned connection 1536471117 to pool. Process finished with exit code 0
但是我换了这个之后,也是可行的
<mappers> <!--<mapper class="cn.dai.mapper.UserAnnotationMapper" />--> <package name="cn.dai.mapper"/> </mappers>
也就是说注册过的地方不可以重复注册
最后采用资源引用 + 接口完全限定名,两者都可以使用
<mappers> <mapper class="cn.dai.mapper.UserAnnotationMapper" /> <mapper resource="mapper/UserMapper.xml"/> </mappers>
补全剩下的注解
package cn.dai.mapper; import cn.dai.pojo.User; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import java.util.List; /** * @author ArkD42 * @file Mybatis * @create 2020 - 05 - 04 - 13:54 */ public interface UserAnnotationMapper { @Select("SELECT * FROM `user`;") List<User> getAllUserList(); @Select("SELECT * FROM `user` WHERE user_id = #{id};") User getUserById(Integer id); @Insert("INSERT INTO `user` VALUES(#{user_id},#{user_name},#{user_password});") int addUser(User user); @Update("UPDATE `user` SET user_name = #{user_name},user_password = #{user_password} WHERE user_id = #{user_id}") int updateUserById(User user); @Delete("DELETE FROM `user` WHERE user_id = #{id};") int deleteUserById(Integer id); }
@Param注解类似结果集字段映射,
主要用于多个参数的绑定匹配
要注意的一点是,注解SQL不能和Mapper映射文件同时配置,
要么注解要么XML,不可以两个都配置同一个接口的抽象SQL方法
更多详细:http://www.mybatis.cn/archives/678.html