定义
MyBatis属于数据库相关的一个Java持久层框架,用于简化JDBC操作。 它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息, 只需要编写对应的接口类而不需要写实现类,就能够完成对数据库的CRUD操作。
每个MyBatis应用程序主要都是使用SqlSessionFactory实例的,一个SqlSessionFactory实例可以通过SqlSessionFactoryBuilder获得。SqlSessionFactoryBuilder可以从一个xml配置文件或者一个预定义的配置类的实例获得。
优点
把sql语句提出到xml文件中,不再有Dao文件。
降低了java代码和sql语句的耦合度
MyBatis的基本配置
MyBatis的基本配置流程如下:
1.导入JAR包
使用MyBatis需要导入MyBatis和数据库驱动jar包,如下所示:
<!-- MyBatis jar包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <!-- mysql驱动jar包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.48</version> </dependency>
2.编写接口类
只需要编写对应的接口类而不需要写实现类,就能够完成对数据库的CRUD操作。
3.编写接口类对应的Mapper映射器
一个接口类对应一个Mapper的xml文件,格式如下:
<?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"> <!-- namespace: 命名空间 (内容为接口类的全名)每一个Mapper.java会有一个对应的Mapper.xml文件 --> <mapper namespace="xxx.xxxMapper"> //... </mapper>
4.编写MyBatis的配置文件
<?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> <!-- 用于控制台输出日志内容 --> <!-- <settings> <setting name="logImpl" value="STDOUT_LOGGING"></setting> </settings> --> <!-- environments标签内部可以配置多个environment,通过default选择出需要加载的一个数据库环境 --> <environments default="development"> <!-- id值为development的开发环境 --> <environment id="development"> <!-- 事务管理,使用JDBC管理 --> <transactionManager type="JDBC"/> <!-- 数据源,使用数据库连接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydb3?useUnicode=true; characterEncoding=utf-8;useSSL=false"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> <!-- 后面还可以配置多个environment --> <environment id="xxx"> ... </environment> </environments> <!-- 配置Mapper映射器的路径 --> <mappers> <mapper resource="mapper/xml/TClassMapper.xml"></mapper> <!-- 如果有多个mapper,则在后面继续添加对应的mapper --> </mappers> </configuration>
配置详解如下:
mappers(引入映射器)
常用的引入映射器方法有3种,如下所示:
- 1.使用文件路径引入映射器
<mappers> <mapper resource="mapper/xml/TClassMapper.xml"></mapper> </mappers>
- 2.使用包名引入映射器
<mappers> <package resource="mapper.xml"></package > </mappers>
- 3.使用类注册引入映射器
<mappers> <class resource="mapper.xml.TClassMapper"></class > </mappers>
MyBatis的组成
MyBatis的组成如下所示:
详解如下:
1.SqlSessionFactoryBuilder(构造器)
根据配置信息或代码生成SqlSessionFactory接口。
2.SqlSessionFactory(工厂接口)
MyBatis的应用都是以SqlSessionFactory的实例为中心,用来生成SqlSession
3.SqlSession(Sql处理器)
SQLSession是一个接口类,类似于JDBC的Connection对象,有如下两种执行方法返回执行结果:
- 获取Mapper接口类映射器
让Mapper映射器通过命名空间和方法名称去找到对应的SQL,发送到数据库并执行,返回结果。
- 直接执行SQL语句
SqlSession支持事务,可以通过commit()和rollback()方法来提交或者回滚事务。
4.Sql Mapper(映射规则及SQL定义)
Sql Mapper即Mapper映射器,MyBatis的新设计组件,由Java接口和XML文件(或注解)构成,需要给出对应的SQL和映射规则。负责发送SQL去执行。并返回结果。
Mapper映射器配置
1.元素
<mapper>里面有如下元素:
select 映射查询语句
最常用最复杂的元素。可以自定义参数,返回结果集等
update 映射更新语句
执行后返回一个整数,代表更新的条数。
delete 映射删除语句
执行后返回一个整数,代表删除的条数。
insert 映射插入语句
执行后返回一个整数,代表插入的条数。
sql 允许定义一部分的sql,然后可以在各个地方引用它 resultMap 用来描述从数据库中查询出来的结果集中来加载对象 cache 给命名空间缓存配置 cache-ref 其他命名空间缓存配置引用 2.元素的属性
id 唯一标识符,需要和Mapper接口类中对应的方法名一样 parameterType 传入参数类型 resultType 返回结果类型
如果返回结果是一个数字,则可以不用写
如果返回结果是一个实体类,则resultType="实体类名"
如果返回结果是一个List<T>集合,则resultType="T"
如果返回结果是一个Map集合,则resultType="map"
resultMap 外部resultMap的命名引用 timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。 fetchSize 影响驱动程序每次批量返回的结果行数。
Mapper的实现原理
MapperProxyFactory中,使用JDK的动态代理生成Mapper接口的代理代理类由动态处理器MapperProxy中调用MapperMethod中的方法处理执行SQL,最后,在MapperMethod中根据执行的方法返回值决定调用SqlSession中的对应方法执行SQL
动态SQL语句
Sql标签
有如下标签:
if 表示判断是否需要添加某个条件,用于SQL语句的拼接
使用if标签的时候,需要使用“where 1=1”, 做sql语句的拼接。避免出现sql语法错误(因为缺少where关键字)
where 用于拼接select和delete语句
set 用于拼接update语句
trim 用于替代set和where标签,可以拼接select、delete、update语句
- if标签
<select id="getEmps" parameterType="entity.Emp" resultType="entity.Emp"> select * from emp where 1=1 <if test="empName!=null">and empName=#{empName}</if> <if test="empAge!=0">and empAge > #{empAge}</if> </select>
- where标签
<select id="getEmpsByWhere" parameterType="entity.Emp" resultType="entity.Emp"> select * from emp <!-- 如果if条件中,有为true的条件,那么会添加一个where关键字,同时会去掉where后面的第一个and关键字 --> <where> <if test="empName!=null">and empName=#{empName}</if> <if test="empAge!=0">and empAge > #{empAge}</if> </where> </select>
- set标签
<update id="updateEmpSet" parameterType="entity.Emp"> update emp <!-- set标签 set中的if标签,条件为真的情况,就会拼在sql语句中, 将最后的“,”去掉。 set中的if标签, 条件都为假的情况,就会出现sql语法错误。 --> <set> <if test="empName!=null">empName=#{empName},</if> <if test="empAge!=0">empAge=#{empAge},</if> <if test="empJob!=null">empJob=#{empJob},</if> <if test="deptNo!=0">deptNo=#{deptNo}</if> </set> <where> <if test="empNo!=0">and empNo=#{empNo}</if> </where> </update>
- trim标签
<!-- trim的使用:替代set和where标签, 通过属性的设置,保证sql语句的语法正确 ) prefix : 添加前缀 prefixOverrides: 删除前面的某个内容 suffix: 添加后缀 suffixOverrides: 删除后面的某个内容 --> <!-- 替代where --> <select id="getEmpsTrim" parameterType="entity.Emp" resultType="entity.Emp"> select * from emp <trim prefix="where" prefixOverrides="and"> <if test="empName!=null">and empName=#{empName}</if> <if test="empAge!=0">and empAge>#{empAge}</if> <if test="empJob!=null">and empJob like #{empJob}</if> </trim> </select> <!-- 替代set --> <select id="updateEmpSet" parameterType="entity.Emp"> update emp <trim prefix="set" suffixOverrides="," suffix=" where empNo=#{empNo}"> <if test="empName!=null">empName=#{empName},</if> <if test="empAge!=0">empAge=#{empAge},</if> <if test="empJob!=null">empJob=#{empJob},</if> <if test="deptNo!=0">deptNo=#{deptNp}</if> </trim> </select>
分页查询
select * from tableName limit begin, maxRow; begin:查询数据的起点 maxRow:表示查询多少的数据(每页的数量) 分页: 每页显示的行数:maxRow 当前是第几页:page 计算出begin: begin (page-1)*maxRow 计算总页数:pages rows/maxRow + 1 计算总行数:rows select count(*) from tableName
导入分页查询插件jar包
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.10</version> </dependency>
在mybatis-config.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> <!-- 分页插件的配置 --> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <!-- value:表示传入参数(page,rows)不合理时的处理方式 为true时:若page表示的页面不存在时,如page<1,那么page设为1;如果page>最后一页,那么page设置为最后一页 为false时:若page表示的页面不存在时,查询内容为空 --> <property name="reasonable" value="true"></property> </plugin> </plugins> .... </configuration>
使用相关类进行分页
public class TestStudent { @Test public void getStudents() throws IOException { SqlSession sqlSession = getSqlSession(); StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class); //调用PageHelper的静态方法设置要分页的页码和每页显示的数量(需要先设置分页的参数,然后才能再查询数据库) PageHelper.startPage(5, 5); List<Student> students = studentMapper.getStudents(); //PageInfo:存放分页相关数据,创建对象的时候,需要一个查询的结果List作为参数, // 需要设置泛型,泛型就是当前查询的实体类 PageInfo<Student> pageInfo = new PageInfo<>(students); System.out.println("总记录数: " + pageInfo.getTotal()); System.out.println("总页数: " + pageInfo.getPages()); System.out.println("每页的数量: " + pageInfo.getPageSize()); System.out.println("当前页: " + pageInfo.getPageNum()); for (Student student : students) { System.out.println(student); } } public SqlSession getSqlSession() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); return sessionFactory.openSession(); } }
使用MyBatis Generator插件
1.说明
使用MyBatis Generator插件可以自动生成数据库对应的表的实体类,mapper映射器类和mapper.xml文件。
2.导入MyBatis Generator插件
点击STS的Help选项,然后点击其中的Eclipse Marketplace。然后在搜索框里面搜索mybatis generator,然后点击下载安装MyBatis Generator插件。如下图所示:
3.使用
在资源文件夹里面右键,点击new选择生成MyBatis Generator Configuration File。如下图所示:
生成的文件如下所示:
<?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> <context id="context1"> <jdbcConnection connectionURL="???" driverClass="???" password="???" userId="???" /> <javaModelGenerator targetPackage="???" targetProject="???" /> <sqlMapGenerator targetPackage="???" targetProject="???" /> <javaClientGenerator targetPackage="???" targetProject="???" type="XMLMAPPER" /> <table schema="???" tableName="???"> <columnOverride column="???" property="???" /> </table> </context> </generatorConfiguration>
然后根据所选的数据库表进行配置,配置好的如下所示:
<?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> <context id="context1"> <!-- 数据库连接 --> <jdbcConnection connectionURL="jdbc:mysql://localhost:3306/crm?useUnicode=true& characterEncoding=utf-8&useSSL=false" driverClass="com.mysql.jdbc.Driver" password="root" userId="root" /> <!-- Java实体类所在包名称和项目名称 --> <javaModelGenerator targetPackage="com.luckylas.crm.entity" targetProject="crm/src/main/java" /> <!-- mapper.xml所在的包(targetPackage)和所在的项目(targetProject) --> <sqlMapGenerator targetPackage="com.luckylas.crm.mapper.xml" targetProject="crm/src/main/java" /> <!-- mapper所在的包(targetPackage)和所在的项目(targetProject) --> <javaClientGenerator targetPackage="com.luckylas.crm.mapper" targetProject="crm/src/main/java" type="XMLMAPPER" /> <!-- tableName标签表示数据库中的表,可以有多个, schema:用于指定实体类的名字,不指定则默认是表名的首字母大写 --> <table schema="User" tableName="user"> <!-- columnOverride表示将数据库表中字段名,在实体类中取一个新的名字。如果不指定,则会默认值--> <!-- <columnOverride column="UId" property="u_id" /> --> </table> </context> </generatorConfiguration>
一个简单的MyBatis实例
创建数据库实体类,和数据库字段一一对应
/** * 班级实体类 * @author luckyliuqs */ public class TClass { private int cid; //班级ID private String cname; //班级名称 public TClass() {} public TClass(int cid, String cname) { super(); this.cid = cid; this.cname = cname; } public int getCid() { return cid;} public void setCid(int cid) {this.cid = cid;} public String getCname() {return cname;} public void setCname(String cname) {this.cname = cname;} @Override public String toString() { return "TClass [cid=" + cid + ", cname=" + cname + "]"; } }
编写数据库接口Mapper类
public interface TClassMapper { public List<TClass> getAll(); //获取所有班级信息 public int insert(TClass tClass); //插入指定班级信息 public void delete(int cid); //删除指定班级信息 public void update(TClass tClass); //更新指定班级信息 }
编写接口类对应的Mapper文件
如下所示:TClassMapper.xml
<?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"> <!-- namespace: 命名空间 (内容为接口Mapper类的全名),每一个Mapper.java会有一个对应的Mapper.xml件 --> <mapper namespace="mapper.TClassMapper"> <!-- id对应为接口Mapper类中的方法名 --> <!-- resultType表示返回结果的类型,这里写入TClass即可,如果返回结果是一个TClass则会返回这个TClass; 如果返回的是多个TClass的集合,则会自动封装为List<TClass>返回 --> <select id="getAll" resultType="entity.TClass"> select * from t_class; </select> <!-- #{s_name}, 这是从方法的参数对象中,取到参数对象中的属性名,得到其属性值 --> <insert id="insert" parameterType="tclassMap"> insert into t_class (c_name) values (#{c_name}); </insert> <delete id="delete"> delete from t_class where c_id=#{c_id}; </delete > <update id="update" parameterType="tclassMap"> update t_class set c_name=#{cname} where c_id=#{c_id}; </update > </mapper>
编写JUnit测试类
/** * 测试类 */ public class TestTClass { @Test public void test() { try { // mybatis的配置文件路径 String resource = "mybatis-config.xml"; // 获取到InputStream流,初始化MyBatis配置环境 InputStream input = Resources.getResourceAsStream(resource); // 得到SqlSessionFactory SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(input); // 得到session,打开和数据库之间的会话 SqlSession session = sessionFactory.openSession(); // 得到接口 TClassMapper clsMapper = session.getMapper(TClassMapper.class); //获取到所有班级信息 List<TClass> list = clsMapper.getAll(); for(TClass cl : list) { System.out.println(cl); } //插入指定班级信息 TClass tClass = new TClass(0,"美工"); clsMapper.insert(tClass); //删除指定班级信息 clsMapper.delete(8); //更新指定班级信息 clsMapper.update(tClass); //提交 session.commit(); session.close(); } catch (IOException e) { e.printStackTrace(); } } }
上述使用MyBatis流程如下:
1.获取MyBatis配置文件 2.获取配置文件的输入流InputStream 3.通过输出流构建工厂SqlSessionFactory 4.通过SqlSessionFactory的openSession()方法获得SqlSession对象 5.通过SqlSession获取到对应实体类的Mapper接口类实例 6.通过此接口类执行对应方法
MyBatis与Hibernate的区别
两者都是持久层框架,区别如下:
Hibernate 是一个标准的ORM框架,比较重量级,学习成本高。
优点:高度封装,使用起来不用写SQL语句,开发周期短
缺点:SQL语句无法优化
应用场景:在于用量不大,并发量小的场景
MyBatis 不是一个ORM框架,只是对JDBC的轻量级封装。
优点:学习成本低,SQL语句可以优化,执行效率高,速度快
缺点:编码量大,开发周期长
应用场景:用户量大,高并发