前言: 最近做公司的项目时,用到的访问数据库CRUD框架为mybatis,实际使用起来经常踩坑,于是总结一下基本使用方法和踩过的坑
基本介绍:mybatis是一款基于JAVA JDBC API [^1] 的持久层框架,它支持将Java POJOs 映射成数据库中对应的记录
[^1]:Java Database connection(java数据库连接)
一. 添加依赖 1 2 3 4 5 <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > x.x.x</version > </dependency >
二. 配置SqlSessionFactory的两种方法 基本定义
sqlSession Factory:
创建sqlSession的工厂,SqlSessionFactory是MyBatis的关键对象,它是个单个数据库映射关系经过编译后的内存镜像.SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象类获得,而SqlSessionFactoryBuilder则可以从XML配置文件或一个预先定制的Configuration的实例构建出SqlSessionFactory的实例.每一个MyBatis的应用程序都以一个SqlSessionFactory对象的实例为核心.同时SqlSessionFactory也是线程安全的,SqlSessionFactory一旦被创建,应该在应用执行期间都存在.在应用运行期间不要重复创建多次,建议使用单例模式
sql session
sqlSession: 应用程序和数据库之间的一个单线程对象,类似于JDBC的connection,线程不安全,是具体执行sql语句的实例
xml 基于xml配置定义数据库源和mapper路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?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 resource ="jdbc.properties" > </properties > <settings > <setting name ="mapUnderscoreToCamelCase" value ="true" /> </settings > <typeAliases > <package name ="cn.itcast.pojo" /> </typeAliases > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" /> <dataSource type ="POOLED" > <property name ="driver" value ="${jdbc.driverClass}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="UserMapper.xml" /> </mappers > </configuration >
Configuration 1 2 3 4 5 6 DataSource dataSource = BlogDataSourceFactory.getBlogDataSource(); TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment("development" , transactionFactory, dataSource); Configuration configuration = new Configuration(environment); configuration.addMapper(BlogMapper.class); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
sqlSession 1 2 3 4 try (SqlSession session = sqlSessionFactory.openSession()) { BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.selectBlog(101 ); }
定义SQL语句的两种方法
1 2 3 4 5 6 7 8 9 <?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 ="org.mybatis.example.BlogMapper" > <select id ="selectBlog" resultType ="Blog" > select * from Blog where id = #{id} </select > </mapper >
1 2 3 4 5 package org.mybatis.example;public interface BlogMapper { @Select ("SELECT * FROM blog WHERE id = #{id}" ) Blog selectBlog (int id) ; }
三. 与SpringBoot的集成 1.配置application.yml文件/application.properties
这一步操作的工作与mybatis.xml的作用类似,定义数据库源和需要扫描的相关mapper的路径
application.properties: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 mybatis.mapperLocations =classpath:mapper/*/*.xml mybatis.typeAliasesPackage =com.xxx.xxx.xxx.webapi.dao mybatis.configuration.map-underscore-to-camel-case =true mybatis.mapper3.identity =MYSQL mybatis.mapper3.notEmpty =true mybatis.mapper3.style =camelhump mybatis.mapper3.mapperLocations =classpath:mapper/*.xml mybatis.mapper3.typeAliasesPackage =com.xxx.xxx.xxx.webapi.domain mybatis.mapper3.pageUsable =true mybatis.mapper3.pageDialect =mysql mybatis.mapper3.pageReasonable =true mybatis.mapper3.pageSupportMethodsArguments =true mybatis.mapper3.pageReturnPageInfo =check mybatis.mapper3.pageParams =count=countSql spring.secure.ds.default.database =bee spring.secure.ds.default.url =jdbc:mysql://001.bi.mysql.test.xxx.info:3308/bee spring.secure.ds.default.username =username spring.secure.ds.default.password =pwd
application.yml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 server: port: 8080 spring: datasource: name: test url: jdbc:mysql://127.0.0.1:3306/depot username: root password: root type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver filters: stat maxActive: 20 initialSize: 1 maxWait: 60000 minIdle: 1 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: select 'x' testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true maxOpenPreparedStatements: 20 mybatis: mapper-locations: classpath:mapping/*.xml type-aliases-package: com.winter.model pagehelper: helperDialect: mysql reasonable: true supportMethodsArguments: true params: count=countSql
2.mapper.xml(这一步可省略) 3.定义Mapper接口
1 2 3 4 5 6 7 8 9 10 11 12 package com.wacai.stanlee.bullseye.webapi.dao;import com.wacai.stanlee.bullseye.webapi.domain.BseAppSidePO;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.annotations.Select;import tk.mybatis.mapper.common.Mapper;import tk.mybatis.mapper.common.MySqlMapper;public interface BseAppSideMapper extends MySqlMapper <BseAppSidePO >, Mapper <BseAppSidePO > { @Select ("select * from bee_app_side where is_deleted=1 and bee_app_main_id=#{beeAppMainId} limit 1" ) BseAppSidePO selectByAppId (@Param("beeAppMainId" ) Integer beeAppMainId) ; }
4.在服务启动的主方法类上添加org.mybatis.spring.annotation.MapperScan配置,作用:在服务启动的时候 全局配置系统对mapper接口扫描。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.winter;import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication @MapperScan ("com.winter.mapper" )public class SpringbootMybatisDemoApplication { public static void main (String[] args) { SpringApplication.run(SpringbootMybatisDemoApplication.class, args); } }
四. 实际使用时的注意事项 1.mybatis对于 in 数组 的支持非常不好,建议用find_in_set(array,num)代替 2.mybatis @Select(“select * from …”)若其中某个字段为字符串 “1,2,3”,而我想将其转换成list,默认的映射无法做到,这时可以自定义一个typeHandler继承BaseTypeHandler,并在mybatis的配置文件中加入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class IntArrayTypeHandler extends BaseTypeHandler<int[]> { @Override public void setNonNullParameter (PreparedStatement ps, int i, int [] parameter, JdbcType jdbcType) throws SQLException { List<String> list = new ArrayList<>(); for (int item : parameter) { list.add(String.valueOf(item)); } ps.setString(i, String.join("," , list)); } @Override public int [] getNullableResult(ResultSet rs, String columnName) throws SQLException { String str = rs.getString(columnName); if (rs.wasNull()) return null ; return Arrays.stream(str.split("," )).mapToInt(Integer::valueOf).toArray(); } @Override public int [] getNullableResult(ResultSet rs, int columnIndex) throws SQLException { String str = rs.getString(columnIndex); if (rs.wasNull()) return null ; return Arrays.stream(str.split("," )).mapToInt(Integer::valueOf).toArray(); } @Override public int [] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { String str = cs.getString(columnIndex); if (cs.wasNull()) return null ; return Arrays.stream(str.split("," )).mapToInt(Integer::valueOf).toArray(); } }
1 2 3 <typeHandlers > <typeHandler handler ="com.jarhf.mybatis.handler.IntArrayTypeHandler" /> </typeHandlers >
3.@Result搭配Ibatis的@Select注解使用
最近在使用mybatis遇到的一个坑,javax.persistence的@Column[^2]在原生ibatis的@Select注解上不起作用,@Column注解只有搭配mybatis预定义方法和才起作用
@Select必须搭配@Result注解来自定义类与表字段的映射 [^2]:Specifies the mapped column for a persistent property or field. If no Column annotation is specified, the default values apply.
1 2 3 4 5 6 7 8 @Select ("select * from bee_deliverys where find_in_set(#{beeAppId},bee_app_id) and channel_id=#{channelId} and is_deleted=0" ) @Results ({ @Result (column = "account_name" , property = "loginName" ), @Result (property = "creator" , column = "authors" ), @Result (property = "blineId" , column = "bee_bline_id" ), @Result (property = "appId" , column = "bee_app_id" ) }) List<PutinAccount> selectByAppIdAndChannel (@Param("channelId" ) Integer channelId, @Param ("beeAppId" ) Integer beeAppId) ;
或者也可以使用xml配置文件中的resultMap解决这一问题
1 2 3 4 5 6 7 8 9 10 11 <resultMap type ="com.test" id ="testResultMap" > <id property ="id" column ="id" /> <result property ="parentId" column ="parentId" /> <result property ="name" column ="name" /> <result property ="enName" column ="enName" /> </resultMap > <select id ="selectList" resultMap ="testResultMap" > select * from test1 </select >
五. 小结 对于框架背后原理的理解可以提升使用效率,本篇只是一个开端,主要总结了一下mybatis基础使用方法,没有涉及到的内容还有很多,例如mybatis的事物管理机制,mybatis连接数据库背后的原理分析,之后再深入学习一下,再做更新:)