MyBatis的几种使用形式。
一、概要
下文意在描述MyBatis的几种使用方式,涵盖了如何使用xml配置的方式连接数据库,此外还有如何使用不包含xml配置的方式连接数据库,最后结合Spring来连接数据库。
二、缘由
我个人认为还是有必要说下缘由的,不然单纯写一篇技术入门随笔简直是浪费时间,同时也是方便未来回忆场景。2020年的今天java体系内大多数公司都开始使用SpringBoot来开发项目,但是我手上还在维护一个老的SpringMVC+Mybatis的项目,基于公司内部技术统一的考虑,还有技术人耿直,我打算以最小的改动将项目迁到SpringBoot上,中间遇到了很多问题其中一项就是Mybatis的配置,使用习惯了spring-boot-start-*的便利,一时竟然搞不定这一堆繁琐的xml配置,于是决定重新梳理下MyBatis,以便迁移配置的时候有理有据不自乱阵脚。
三、Mybatis几种使用形式
1. 最原始的xml配置的形式。
XmlMain.java : 入口方法
Blog.java : 数据库对应的实体类
BlogMapper.xml : xml 配置的sql
mybatis-config.xml :MyBatis的配置文件
public class XmlMain { public static void main(String[] args) { try { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession(); Blog blog = (Blog) session.selectOne("com.wx.test.mybatis.mapper.BlogMapper.selectBlog", 1); System.out.println(blog.toString()); } catch (IOException e) { e.printStackTrace(); } } }
public class Blog { private Integer id; private String userName; private Timestamp date; private Integer score; //todo getter and setter 或者使用Lombok }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.wx.test.mybatis.mapper.BlogMapper"> <resultMap id="blog" type="com.wx.test.mybatis.entity.Blog"> <result property="id" column="ID"/> <result property="userName" column="username"/> <result property="date" column="date"/> <result property="score" column="score"/> </resultMap> <select id="selectBlog" resultMap="blog" parameterType="int"> select * from a_user where id = #{id} </select> </mapper>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/order?allowMultiQueries=true"/> <property name="username" value="root"/> <property name="password" value="1234"/> </properties> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="mapper/BlogMapper.xml"/> </mappers> </configuration>
xml形式小结,这是MyBatis最开始设计的初衷。将sql编写抽离出来,在独立的一个xml文件中按一定格式编写,然后交由内部执行器执行。我个人认为上面最核心的代码 是 Blog blog = (Blog) session.selectOne("com.wx.test.mybatis.mapper.BlogMapper.selectBlog", 1); (当然MyBatis官网认为SqlSessionFactory是最核心的)MyBatis内部会在恰当的时间将BlogMapper.xml 内的sql加载到内存中,并将每一个sql块以Statement保存起来。这行代码主要目的就是指定执行的Statement是哪一个,然后让session去执行。
2. 不以xml配置的方式
先说下我的理解:不以xml配置的方式就是去掉 mybatis-config.xml 和 BlogMapper.xml,用BlogMapper.java加上注解sql来替代。
理解的依据:我在官网上了解到只有两种形式构建SqlSessionFactory,一种是在mybatis-config.xml中配置好Configuration,然后通过流的方式读入配置文件,构建出SqlSessionFactory(即第一种方式);另一种是通过MyBatis提供的配置类自己实例化(这里涉及到BlogMapper.java,而非BlogMapper.xml) 。我没有找到仅去除mybatis-config.xml 而保留 BlogMapper.xml 的方式(这种方式我卡在了如何给Configuration设置xml路径的问题上,如果读者了解相关解法,欢迎指教)。
类文件说明:
MainTest.java : 入口文件
BlogMapper.java : 接口用来支撑注解sql
Blog.java : 实体同上
public class MainTest { public static void main(String[] args) { DataSource dataSource = getDataSource(); TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment("development", transactionFactory, dataSource); Configuration configuration = new Configuration(environment); configuration.addMappers("com.wx.test.mybatis.mapper"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); try (SqlSession session = sqlSessionFactory.openSession()) { BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.selectBlog(1); System.out.println("[RESULT]-------" + blog.toString()); } } private static DataSource getDataSource() { Properties properties = new Properties(); properties.put("driver", "com.mysql.jdbc.Driver"); properties.put("url", "jdbc:mysql://localhost:3306/order?allowMultiQueries=true"); properties.put("username", "root"); properties.put("password", "1234"); PooledDataSourceFactory pooledDataSourceFactory = new PooledDataSourceFactory(); pooledDataSourceFactory.setProperties(properties); return pooledDataSourceFactory.getDataSource(); } }
public interface BlogMapper { @Select("select * from a_user where id = 1") Blog selectBlog(int i); }
非xml形式小结: 这样下来三个文件就搞定了,纯java代码简洁了不少,不过似乎和我预想的还是不太一样,我印象中既可以用BeanMapper.java的反射特性,也可以同时结合xml的处理复杂sql的优势,那么是不是还有别的方式。
maven依赖说明:上面两种方式是只引入 mybatis.jar,主要的依赖如下
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.4</version> </dependency> <!-- 驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.17</version> </dependency>
3. MyBatis-Spring 形式
使用mybatis-spring-2.0.5.jar 我发现解决了我第二种方式的问题,既可以使用反射特性,又可以结合xml的sql配置文件解决复杂sql的优势,同时还去除了mybatis-confiration.xml的配置。
MainTest.java : 入口文件
DatabaseConfig.java : java注解配置文件
BlogService.java : 主要是用来注入 BlogMapper.java对象,方便测试
Blog.java : 实体(同上)
BlogMapper.java : 接口用来支撑注解sql或者映射xml中sql(同上)
BlogMapper.xml :xml sql(同上)
public class MainTest { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(DatabaseConfig.class); BlogService blogService = ctx.getBean(BlogService.class); blogService.test(); } }
@Configuration @MapperScan("com.wx.test.mybatis.mapper") public class DatabaseConfig { @Bean public BlogService blogService() { return new BlogService(); } @Bean public SqlSessionFactory sqlSessionFactoryBean() throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource()); Resource[] mapperXml = new PathMatchingResourcePatternResolver().getResources( "classpath" + ":mapper/*.xml"); factoryBean.setMapperLocations(mapperXml); return factoryBean.getObject(); } private DataSource dataSource() { Properties properties = new Properties(); properties.put("driver", "com.mysql.jdbc.Driver"); properties.put("url", "jdbc:mysql://localhost:3306/order?allowMultiQueries=true"); properties.put("username", "root"); properties.put("password", "1234"); PooledDataSourceFactory pooledDataSourceFactory = new PooledDataSourceFactory(); pooledDataSourceFactory.setProperties(properties); return pooledDataSourceFactory.getDataSource(); } }
@Component public class BlogService { @Autowired private BlogMapper blogMapper; public void test() { Blog blog = blogMapper.selectBlog(1); System.out.println("[TEST]-------" + blog.toString()); } }
说下maven依赖。因为引入了Spring的工厂,所以额外加入了Spring的包,我在里面没有标注,如果想要测试可以直接引入spring-context这个jar包就行。我是spring-boot工程,所以测试的是有用的是 spring-boot-start-web,这个看个人具体的使用的。
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.5</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.2.RELEASE</version> </dependency>
四、总结
到这里我已经清楚之前的项目是使用的第一种方式,和我预想的还是不太一样。后续我准备分两步去做。首先会先按照第一方式迁到spring-boot工程,之后在找时间改成maybatis-spring的形式。原因也很简单,第二种直接在mapper中注解的形式肯定是不满足业务的。第三种需要花时间去改造所有的BeanMapper.java,这个不太现实----懒(文中有什么不对的地方欢迎各路大神指正)。
五、番外篇---- mybatis-spring-boot
BlogMapper.xml (同上)
Blog.java (同上)
BlogMapper.java (同上)
@RestController public class BlogController { @Autowired private BlogService blogService; @GetMapping("/test") public void test() { blogService.test(); } }
@Service public class BlogService { @Autowired private BlogMapper blogMapper; public void test() { Blog blog = blogMapper.selectBlog(1); System.out.println(blog.toString()); } }
spring: application: name: mybatis-server datasource: driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/gemini_bet?allowMultiQueries=true&useUnicode=true&characterEncoding=utf8 username: root password: 1234 server: port: 8081 mybatis: type-aliases-package: com.wx.entity mapper-locations: classpath:mapper/*.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.3.3.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> <version>2.3.3.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.17</version> </dependency>
小结:mybatis-spring-boot-start 使用起来就超级简洁了,没有了之前xml或者java等一些列繁杂的SqlssessionFactory配置。直接在yml配置一些东西就好了,这就是大名鼎鼎的约定大于配置。其实配置还在,只不过通过自动装配的思想剥离到了mybatis-spring-boot-start 中。