mybatis概念
mybatis和hibernate一样,都是orm框架且是开源的框架,但是相对来说,mybatis的使用比hibernate更广泛,hibernate有个优点就是无缝移植,一个公司不可能频繁的更换数据库,所以这个优点也就很鸡肋,且mybatis较hibernate开发更轻量,更受欢迎
mybatis对比hibernate:
mybatis | hibernate |
---|---|
轻量级 | 重量级 |
半自动化 | 全自动化 |
sql | hql(但也可以使用sql,但违背了hibernate的初衷) |
扩展性、迁移性比较差 | 无缝移植 |
基于idea逆向工程的创建
这里博主是基于maven的创建
导入pom依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xiaoyang</groupId>
<artifactId>mybatisprim</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>mybatisprim Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- ********************** junit单元测试依赖 ********************** -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- ********************** Java Servlet API ********************** -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.0</version>
<scope>provided</scope>
</dependency>
<!-- ********************** Mybatis依赖 ********************** -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- ********************** Mysql JDBC驱动 ********************** -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
<!-- ********************** 日志配置 ********************** -->
<!--记得修改mybatis.cfg.xml添加如下内容-->
<!--<setting name="logImpl" value="LOG4J2"/>-->
<!--核心log4j2jar包-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.9.1</version>
</dependency>
<!--web工程需要包含log4j-web,非web工程不需要-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<version>2.9.1</version>
</dependency>
<!--mybatis分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.2</version>
</dependency>
</dependencies>
<build>
<finalName>mybatisprim</finalName>
<resources>
<!--解决mybatis-generator-maven-plugin运行时没有将XxxMapper.xml文件放入target文件夹的问题-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<!--解决mybatis-generator-maven-plugin运行时没有将jdbc.properites文件放入target文件夹的问题-->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>jdbc.properties</include>
<include>*.xml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<dependencies>
<!--使用Mybatis-generator插件不能使用太高版本的mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
</dependencies>
<configuration>
<overwrite>true</overwrite>
</configuration>
</plugin>
</plugins>
</build>
</project>
jdbc.properties:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8
jdbc.username=xiaoyang
jdbc.password=xxx
设置web.xml的版本:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"></web-app>
完成以上步骤后,安装逆向工程所需要的几个插件:
Free mybatis plugin
Mybatis generator
mybatis tools
maven helper
关于几个插件的具体介绍,可参考这篇文章:https://blog.csdn.net/yangshijin1988/article/details/63258960/
mybatis.cfg.xml配置:
<?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"/>
<settings>
<setting name="logImpl" value="LOG4J2"/>
</settings>
<!-- 别名 -->
<typeAliases>
<!--<typeAlias type="com.javaxl.model.Book" alias="Book"/>-->
</typeAliases>
<!--分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
<!-- 配置mybatis运行环境 -->
<environments default="development">
<environment id="development">
<!-- type="JDBC" 代表使用JDBC的提交和回滚来管理事务 -->
<transactionManager type="jdbc"/>
<!-- mybatis提供了3种数据源类型,分别是:POOLED,UNPOOLED,JNDI -->
<!-- POOLED 表示支持JDBC数据源连接池 -->
<!-- UNPOOLED 表示不支持数据源连接池 -->
<!-- JNDI 表示支持外部数据源连接池 -->
<dataSource type="POOLED">
<property name="driver"
value="${jdbc.driver}"/>
<property name="url"
value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/xiaoyang/mapper/BookMapper.xml"/>
</mappers>
</configuration>
配置逆向生成的配置文件 generatorConfig.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>
<!-- 引入配置文件 -->
<properties resource="jdbc.properties"/>
<!--指定数据库jdbc驱动jar包的位置-->
<classPathEntry
location="E:\maven\mvn-repository\mysql\mysql-connector-java\5.1.44\mysql-connector-java-5.1.44.jar"/>
<!-- E:\maven\mvn-repository\mysql\mysql-connector-java\5.1.44-->
<!-- 一个数据库一个context -->
<context id="infoGuardian">
<!-- 注释 -->
<commentGenerator>
<property name="suppressAllComments" value="true"/><!-- 是否取消注释 -->
<property name="suppressDate" value="true"/> <!-- 是否生成注释代时间戳 -->
</commentGenerator>
<!-- jdbc连接 -->
<jdbcConnection driverClass="${jdbc.driver}"
connectionURL="${jdbc.url}" userId="${jdbc.username}" password="${jdbc.password}"/>
<!-- 类型转换 -->
<javaTypeResolver>
<!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) -->
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 01 指定javaBean生成的位置 -->
<!-- targetPackage:指定生成的model生成所在的包名 -->
<!-- targetProject:指定在该项目下所在的路径 -->
<javaModelGenerator targetPackage="com.xiaoyang.model"
targetProject="src/main/java">
<!-- 是否允许子包,即targetPackage.schemaName.tableName -->
<property name="enableSubPackages" value="false"/>
<!-- 是否对model添加构造函数 -->
<property name="constructorBased" value="true"/>
<!-- 是否针对string类型的字段在set的时候进行trim调用 -->
<property name="trimStrings" value="false"/>
<!-- 建立的Model对象是否 不可改变 即生成的Model对象不会有 setter方法,只有构造方法 -->
<property name="immutable" value="false"/>
</javaModelGenerator>
<!-- 02 指定sql映射文件生成的位置 -->
<sqlMapGenerator targetPackage="com.xiaoyang.mapper"
targetProject="src/main/java">
<!-- 是否允许子包,即targetPackage.schemaName.tableName -->
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!-- 03 生成XxxMapper接口 -->
<!-- type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象 -->
<!-- type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象 -->
<!-- type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口 -->
<javaClientGenerator targetPackage="com.xiaoyang.mapper"
targetProject="src/main/java" type="XMLMAPPER">
<!-- 是否在当前路径下新加一层schema,false路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!-- 配置表信息 -->
<!-- schema即为数据库名 -->
<!-- tableName为对应的数据库表 -->
<!-- domainObjectName是要生成的实体类 -->
<!-- enable*ByExample是否生成 example类 -->
<!--<table schema="" tableName="t_book" domainObjectName="Book"-->
<!--enableCountByExample="false" enableDeleteByExample="false"-->
<!--enableSelectByExample="false" enableUpdateByExample="false">-->
<!--<!– 忽略列,不生成bean 字段 –>-->
<!--<!– <ignoreColumn column="FRED" /> –>-->
<!--<!– 指定列的java数据类型 –>-->
<!--<!– <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" /> –>-->
<!--</table>-->
<table schema="" tableName="t_easyui_book" domainObjectName="Book"
enableCountByExample="false" enableDeleteByExample="false"
enableSelectByExample="false" enableUpdateByExample="false">
<!-- 忽略列,不生成bean 字段 -->
<!-- <ignoreColumn column="FRED" /> -->
<!-- 指定列的java数据类型 -->
<!-- <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" /> -->
</table>
</context>
</generatorConfiguration>
配置maven运行generator命令:
Name项可随便取名,完成后,如下图运行生成即可:
创建成功后的项目结构:
附session事务助手类:
package com.xiaoyang.util;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
/**
* @author xiaoyang
* @create 2020-10-20 11:12
*/
public class SessionUtil {
private static SqlSessionFactory sessionFactory;
private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();
static {
sessionFactory = new SqlSessionFactoryBuilder().build(SessionUtil.class.getResourceAsStream("/mybatis.cfg.xml"));
}
public static SqlSession openSession() {
SqlSession session = threadLocal.get();
if (null == session) {
session = sessionFactory.openSession();
threadLocal.set(session);
}
return session;
}
public static void main(String[] args) {
SqlSession session = openSession();
System.out.println(session.getConnection());
session.close();
// System.out.println(session.getConnection());
}
}
mybatis动态sql及结果集处理
<!--动态sql foreach-->
<select id="selectBooksIn" resultType="com.xiaoyang.model.Book" parameterType="java.util.List">
select * from t_easyui_book where id in
<foreach collection="bookIds" open="(" close=")" separator="," item="bid">
#{bid}
</foreach>
</select>
<!--模糊查询 三种方式-->
<select id="seletBooksLike1" resultType="com.xiaoyang.model.Book" parameterType="java.lang.String">
select * from t_easyui_book where name like #{bname}
</select>
<select id="seletBooksLike2" resultType="com.xiaoyang.model.Book" parameterType="java.lang.String">
select * from t_easyui_book where name like '${bname}'
</select>
<select id="seletBooksLike3" resultType="com.xiaoyang.model.Book" parameterType="java.lang.String">
select * from t_easyui_book where name like concat(concat('%',#{bname}),'%')
</select>
<!--结果集处理-->
<select id="list1" resultType="com.xiaoyang.model.Book" resultMap="BaseResultMap">
select * from t_easyui_book
</select>
<select id="list2" resultType="com.xiaoyang.model.Book">
select * from t_easyui_book
</select>
<select id="list3" resultType="com.xiaoyang.model.Book" parameterType="com.xiaoyang.model.vo.BookVo">
select * from t_easyui_book where id in
<foreach collection="bookIds" open="(" close=")" separator="," item="bid">
#{bid}
</foreach>
</select>
<select id="list4" resultType="java.util.Map" parameterType="java.util.Map">
select * from t_easyui_book where id in
<foreach collection="bookIds" open="(" close=")" separator="," item="bid">
#{bid}
</foreach>
</select>
<select id="list5" resultType="java.util.Map" parameterType="java.util.Map">
select * from t_easyui_book where id=#{bid}
</select>
<select id="list6" resultType="com.xiaoyang.model.Book" parameterType="java.util.Map">
select * from t_easyui_book where price > #{min} and price < #{max}
</select>
参数: resultType和resultMap都是执行查询语句时返回的结果集
resultType:
resultType相对与resultMap而言更简单一点,需数据库表中的字段名和实体类中的属性完全一致
resultMap:
resultMap可以实现将查询结果映射为复杂类型的pojo,例如:
<resultMap id="BaseResultMap" type="com.xiaoyang.model.Book">
<constructor>
<idArg column="id" jdbcType="BIGINT" javaType="java.lang.Long"/>
<arg column="name" jdbcType="VARCHAR" javaType="java.lang.String"/>
<arg column="pinyin" jdbcType="VARCHAR" javaType="java.lang.String"/>
<arg column="cid" jdbcType="BIGINT" javaType="java.lang.Long"/>
<arg column="author" jdbcType="VARCHAR" javaType="java.lang.String"/>
<arg column="price" jdbcType="REAL" javaType="java.lang.Float"/>
<arg column="image" jdbcType="VARCHAR" javaType="java.lang.String"/>
<arg column="publishing" jdbcType="VARCHAR" javaType="java.lang.String"/>
<arg column="description" jdbcType="VARCHAR" javaType="java.lang.String"/>
<arg column="state" jdbcType="INTEGER" javaType="java.lang.Integer"/>
<arg column="deployTime" jdbcType="TIMESTAMP" javaType="java.util.Date"/>
<arg column="sales" jdbcType="INTEGER" javaType="java.lang.Integer"/>
</constructor>
</resultMap>
Mapper层:
package com.xiaoyang.mapper;
import com.xiaoyang.model.Book;
import com.xiaoyang.model.vo.BookVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface BookMapper {
int deleteByPrimaryKey(Long id);
int insert(Book record);
int insertSelective(Book record);
Book selectByPrimaryKey(Long id);
int updateByPrimaryKeySelective(Book record);
int updateByPrimaryKey(Book record);
/**
* 如果形参要在mapper.xml中使用就需要加上注解param
*
* @param bookIds
* @return
*/
List<Book> selectBooksIn(@Param("bookIds") List bookIds);
/**
* mybatis对模糊查询三种方式
* #{}自带引号
* ${}有sql注入的风险
* concat
*
* @param bname
* @return
*/
List<Book> seletBooksLike1(@Param("bname") String bname);
List<Book> seletBooksLike2(@Param("bname") String bname);
List<Book> seletBooksLike3(@Param("bname") String bname);
/**
* mybatis结果集处理的五种情况
*
* @return
*/
List<Book> list1();
List<Book> list2();
List<Book> list3(BookVo bookVo);
List<Map> list4(Map map);
Map list5(Map map);
/**
* 特殊字符的处理
* @param bookVo
* @return
*/
List<Book> list6(BookVo bookVo);
List<Map> listPager(Map map);
}
分页插件PageHelper的使用
Mybatis的分页功能很弱,它是基于内存的分页(查出所有记录再按偏移量offset和边界limit取结果),在大数据量的情况下这样的分页基本上是没有用的
使用分页插件:
1、导入pom依赖
<!--mybatis分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.2</version>
</dependency>
2、Mybatis.cfg.xml配置拦截器
<!-- 别名 -->
<typeAliases>
<!--<typeAlias type="com.javaxl.model.Book" alias="Book"/>-->
</typeAliases>
<!--分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
plugin 元素标签放在typeAliases后,避免引起报错
3、使用PageHelper进行分页(需要分页助手类,可以没有,但是需要定义页大小和行数)
public List<Map> listPager(Map map, PageBean pageBean) {
//如果pagebean里是分页的,分页插件开始分页,将页码和页记录数放入插件初始化
if (pageBean != null && pageBean.isPagination()) {
PageHelper.startPage(pageBean.getPage(), pageBean.getRows());
}
List<Map> maps = bookMapper.listPager(map);
if (pageBean != null && pageBean.isPagination()) {
PageInfo pageInfo=new PageInfo(maps);
System.out.println("总记录数:" + pageInfo.getTotal());
System.out.println("当前页:" + pageInfo.getPageNum());
System.out.println("页大小:" + pageInfo.getPageSize());
pageBean.setTotal(pageInfo.getTotal()+"");
System.out.println("总页数:" + pageBean.getMaxPage());
}
return maps;
}
分页助手类:
package com.xiaoyang.util;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.Map;
public class PageBean implements Serializable {
private static final long serialVersionUID = 2422581023658455731L;
//页码
private int page=1;
//每页显示记录数
private int rows=10;
//总记录数
private int total=0;
//是否分页
private boolean isPagination=true;
//上一次的请求路径
private String url;
//获取所有的请求参数
private Map<String,String[]> map;
public PageBean() {
super();
}
//设置请求参数
public void setRequest(HttpServletRequest req) {
String page=req.getParameter("page");
String rows=req.getParameter("rows");
String pagination=req.getParameter("pagination");
this.setPage(page);
this.setRows(rows);
this.setPagination(pagination);
this.url=req.getContextPath()+req.getServletPath();
this.map=req.getParameterMap();
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Map<String, String[]> getMap() {
return map;
}
public void setMap(Map<String, String[]> map) {
this.map = map;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public void setPage(String page) {
if(null!=page&&!"".equals(page.trim()))
this.page = Integer.parseInt(page);
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
this.rows = rows;
}
public void setRows(String rows) {
if(null!=rows&&!"".equals(rows.trim()))
this.rows = Integer.parseInt(rows);
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public void setTotal(String total) {
this.total = Integer.parseInt(total);
}
public boolean isPagination() {
return isPagination;
}
public void setPagination(boolean isPagination) {
this.isPagination = isPagination;
}
public void setPagination(String isPagination) {
if(null!=isPagination&&!"".equals(isPagination.trim()))
this.isPagination = Boolean.parseBoolean(isPagination);
}
/**
* 获取分页起始标记位置
* @return
*/
public int getStartIndex() {
//(当前页码-1)*显示记录数
return (this.getPage()-1)*this.rows;
}
/**
* 末页
* @return
*/
public int getMaxPage() {
int totalpage=this.total/this.rows;
if(this.total%this.rows!=0)
totalpage++;
return totalpage;
}
/**
* 下一页
* @return
*/
public int getNextPage() {
int nextPage=this.page+1;
if(this.page>=this.getMaxPage())
nextPage=this.getMaxPage();
return nextPage;
}
/**
* 上一页
* @return
*/
public int getPreivousPage() {
int previousPage=this.page-1;
if(previousPage<1)
previousPage=1;
return previousPage;
}
@Override
public String toString() {
return "PageBean [page=" + page + ", rows=" + rows + ", total=" + total + ", isPagination=" + isPagination
+ "]";
}
}
mybatis特殊字符的处理
mybatis特殊字符处理主要是对mapper的xml文件进行的处理:
例如大于符号、小于符号和元素标签<>冲突,所以可这样:
> >
< <
& &
空格
<![CDATA[ <= ]]> 把有特殊符号的用这种方式包括起来,可以任意使用特殊符号
<select id="list6" resultType="com.xiaoyang.model.Book" parameterType="java.util.Map">
select * from t_easyui_book where price > #{min} and price < #{max}
</select>
over…