Mybatis

    科技2026-06-11  1

    2020年9月10日19:29:16

    一、什么是Mybatis

    1.1、什么是mybatis

    Mybatis是一款优秀的持久层框架他支持定制化SQL、储存过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。Mybatis可以使用简单的XML或注解来配置和映射原生类型、接口和java的POJO(Plain Old java Objects,普通老式java对象)为数据库中的记录。Mybatis本是apache的一个开源项目iBtis,2010年这个项目由Apache software foundation前移到了google code,并且改名为MaBatis。2013年11月迁移到GItHub。

    1.2、持久化

    数据持久化:就是将程序的数据在持久状态和瞬时转化的过程。

    持久状态;比如数据库(JDBC),IO文件持久化。

    瞬时状态:比如内存,断电即失。

    生活中冷藏也是一种持久化。

    为什么需要持久化?

    避免断电丢失内存太贵

    1.3、持久层

    Dao层、Service层、Controller层

    王朝的那个持久化工作的代码块层界线明显

    1.4、为什么需要MyBatis?

    帮助程序员将数据库存入到数据库中。

    增加开发效率

    传统JDBC代码太复杂了,简化代码,(框架)自动化管理。

    易上手,易使用。(技术没有高低之分)

    sql与代码分离,提高了维护性。使程序设计清晰、易维护、易测试。将业务逻辑与数据访问逻辑分离。灵活提供xml标签,支持编写动态SQL。

    重要的是:使用的人多!

    二、第一次使用MyBatis程序

    思路:搭建环境–>导入MyBatis–>编写代码–>测试!

    2.1、搭建环境

    2.1.1、搭建数据

    CREATE TABLE `user` ( `id` int(20) NOT NULL AUTO_INCREMENT, `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `pws` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; INSERT INTO `user` VALUES (1, '悟空', '123'); INSERT INTO `user` VALUES (2, '八戒', '321'); INSERT INTO `user` VALUES (3, '沙僧', '000');

    2.1.2、新建项目

    新建一个maven项目
    获取mybatis <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency>
    删除sre文件
    在mop.xml文件中导入maven依赖
    <!--导入依赖--> <dependencies> <!--sql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.16</version> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <!--防止导包出问题--> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build> </project>

    2.2、创建.xml配置文件

    创建module。

    配置mybatis-config.xml文件

    易忘点:

    驱动使在mysql包下的jdbc包里。useUnicode=true(安全连接)useUnicode=true(Unicode编码可以正常输出,作用:可以使用中文)characterEncoding=UTF-8(解决了读取数据库产生的数据乱码的问题,从数据库读数据和写数据时MySQL的默认编码非UTF8编码,需要设置字符集编码为utf8 ) <?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核心配置--> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <!-- 与&同意 Unicode编码可以正常显示中文 时区--> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/> <property name="username" value="root"/> <property name="password" value="123"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/lyx/mapper/StuMapper.xml"/> </mappers> </configuration>

    编写MyBatis工具类

    package main.java.com.lyx.dao; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; /** * 工具类 * 获取sqlSessionFactory --> sqlSession */ public class MybatisUtils { //提升作用域 private static SqlSessionFactory sqlSessionFactory; static { try { //使用MyBatis第一步: 获取sqlSessionFactory对象 String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } //有了sqlSessionFactory对象,获取到SqlSession的实例了。 //SqlSession中包含了面向数据库执行Sql命令的所有方法。 public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }

    2.3、编写代码

    实体类
    package main.java.com.lyx.pojo; //实体类 public class user { private int id; private String naem; private String pws; public user() { } public user(int id, String naem, String pws) { this.id = id; this.naem = naem; this.pws = pws; } public int getId() { return id; } public String getNaem() { return naem; } public String getPws() { return pws; } public void setId(int id) { this.id = id; } public void setNaem(String naem) { this.naem = naem; } public void setPws(String pws) { this.pws = pws; } @Override public String toString() { return "user{" + "id=" + id + ", naem='" + naem + '\'' + ", pws='" + pws + '\'' + '}'; } }
    dao层mapper接口
    public interface User_dao { //遍历集合 List<Stu> getStu(); //根据id查询单条数据 List<Stu> getStuId(int id); //添加数据(数据库增删改需要提交事务才行!) int addStu(Stu stu); //修改Stu int updateStu(Stu stu); //删除一条数据 int deleteStu(int id); //Map测试 int addMap(Map<String,Object> map); }
    接口实现
    (在mapper中)由原来的的UserDaoimp转变为一个mapper配置文件 <?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:绑定一个对应的Dao/Mapper接口--> <mapper namespace="com.lyx.dao.User_dao"> <!--select语句 传参:parameter:类型Type,集合用Map--> <select id="getUserList" resultType="com.lyx.pojo.User"> select * from mybatis.user </select> <select id="getStu" resultType="com.lyx.pojo.Stu"> select * from stu </select> <select id="getStuId" parameterType="int" resultType="com.lyx.pojo.Stu"> select * from Stu where id=#{id} </select> <!-- 对象中的属性可以直接取出来使用--> <insert id="addStu" parameterType="com.lyx.pojo.Stu" > insert into mybatis.Stu (id,name,age) values (#{id},#{name},#{age}) </insert> <update id="updateStu" parameterType="com.lyx.pojo.Stu"> update mybatis.stu set name=#{name},age=#{age} where id=#{id} </update> <delete id="deleteStu" parameterType="int"> delete from mybatis.stu where id=#{id} </delete> <!--测试Map--> <insert id="addMap" parameterType="map" > insert into mybatis.stu (id,name,age) values (#{a},#{b},#{c}) </insert> </mapper>

    注意点:增删改需要提交事务(sqlSession.commit();)

    2.4、测试

    注意点:

    测试类最好写在与被测试类的路径类似 package com.lyx; import com.lyx.mapper.StuMapper; import com.lyx.pojo.Stu; import com.lyx.util.StuUtil; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; public class StuTest { @Test public void test(){ //调用util中的getSession方法获取到sqlSession方法 SqlSession sqlSession = StuUtil.getSqlSession(); //调用sqlSession方法获取 StuMapper mapper = sqlSession.getMapper(StuMapper.class); List<Stu> stu = mapper.getStu(); System.out.println(stu); } @Test public void TestId(){ SqlSession sqlSession = mybatisUtil.getSqlSession(); StuMapper mapper = sqlSession.getMapper(StuMapper.class); List<Stu> stuId = mapper.getStuId(1); System.out.println(stuId); sqlSession.close(); } } 总结:失败的原因只有一个那就是懒性

    三、拓展

    1、万能的Map

    接口

    //Map测试 int addMap(Map<String,Object> map);

    接口xml文件

    <!--测试Map--> <insert id="addMap" parameterType="map" > insert into mybatis.stu (id,name,age) values (#{a},#{b},#{c}) </insert>

    测试

    @Test public void addMap(){ SqlSession sqlSession = mybatisUtil.getSqlSession(); StuMapper mapper = sqlSession.getMapper(StuMapper.class); Map<String, Object> map = new HashMap<String, Object>(); map.put("a",5); map.put("b","Map测试!"); map.put("c",333333); mapper.addMap(map); sqlSession.commit(); sqlSession.close(); }

    ##2、模糊查询

    //接口代码 //模糊查询 List<Stu> getStuN(String name); //接口.xml代码 <select id="getStuN" resultType="com.lyx.pojo.Stu"> select * from mybatis.stu where name like "%"#{name}"%" </select> //测试 @Test public void getStuN(){ SqlSession sqlSession = mybatisUtil.getSqlSession(); StuMapper mapper = sqlSession.getMapper(StuMapper.class); List<Stu> stuN = mapper.getStuN("李"); System.out.print(stuN); sqlSession.close(); }

    四、配置优化

    4.1、属性

    在resources中新建.properties文件 driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&&characterEncoding=UTF-8&&serverTimezone=Asia/Shanghai username=root password=123 在mybatis-config。xml文件中导入 <!-- 方式一 --> <properties resource="db.properties"/> <!-- 方式二 --> <properties resource="org/mybatis/example/config.properties"> <property name="username" value="dev_user"/> <property name="password" value="F2Fa3!33TYyg"/> </properties>

    注意点:

    ①.properties文件和.xml数据库连接的url部分中的&&的解读方式不一样,在.xml文件中&amp; ,在.properties文件应该被写成&&

    ​ ②在xml文件中所有的标签都有其对应的位置。

    ​ ③方式二优先执行外部映入文件中的内容。

    4.2、别名

    类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。 实体类别名 (mybatis的mapper层是是不能起别名的) <!-- mybatis文件中配置 配置别名--> <typeAliases > <typeAlias type="lyx.pojo.Stu" alias="Stu"/> </typeAliases> <!--接口.xml文件中使用--> <select id="getStu" resultType="Stu"> select * from stu </select> 包别名:指定一个包名,MyBatis 会在包名下面搜索需要的 <!-- mybatis文件中配置 --> <typeAliases> <package name="com.lyx.mapper"/> </typeAliases>

    注意点:

    在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名 。

    接口不可以使用第一种方法。(namespace属性:在MyBatis中,Mapper中的namespace用于绑定Dao接口的,即面向接口编程。

    它的好处在于当使用了namespace之后就可以不用写接口实现类,业务逻辑会直接通过这个绑定寻找到相对应的SQL语句进行对应的数据处理,不可以定义别名)

    **两者区别:**第一种可以自定义别名,第二种不行(如果个别需要自定义可以使用注解起别名自定义别名),如果实体类多,建议使用第二种,反之第一种。

    注解别名:在实体类中采用注解方式,起别名 import org.apache.ibatis.type.Alias; @Alias("zjbm") public class Stu {} 注意:是导入org.apache.ibatis.type中的Alias

    4.3、设置

    https://mybatis.org/mybatis-3/zh/configuration.html#properties

    4.4、映射器

    作用:告诉 MyBatis 去哪里找映射文件 (寻找sql)

    方式一:使用相对于类路径的资源引用

    <mappers> <mapper resource="com/lyx/mapper/StuMapper.xml"/> </mappers>

    方式二:使用映射器接口实现类的完全限定类名

    <mamppers> <mapper class="com.lyx.mapper.StuMapper"/> </mamppers>

    方式三:将包内的映射器接口实现全部注册为映射器

    <mappers> <package name="com.lyx.mapper"/> </mappers> 后两者注意:实体类与映射文件必须在统一包内并且命名一致。

    五、日志

    5.1、日志工厂

    如果一个数据库操作出现异常,日志是最好的排查错误的助手。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EdQVQ9zk-1604538561160)(E:\桌面\Markdown笔记\1604132888073.png)]

    有效值:SLF4J、LOG4J 、 LOG4J2 、 JDK_LOGGING 、 COMMONS_LOGGING 、 STDOUT_LOGGING 、 NO_LOGGING (不同的有效值,实现方式不同,输出不同)

    loglmpl没有默认值

    在mybatis中具体使用哪种日志实现,在设置中指定。

    STDOUT_LOGGING标准日志输出

    <!-- settings标签位置必须在properties与typeAliases标签中间--> <settings> <!--标准日志工厂--> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>

    5.2、LOG4J的使用

    5.21、什么是LOG4J?

    控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog、守护进程等控制每一条日志的输出格式定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过还可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

    5.22、基本使用

    导入log4j的包 <!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> 创建log4j的.properties文件 #将等级为DEBUG的日志信息输出到console和file这两个目的地,console和fiLe的定义在下面的代码 log4j.rootLogger=DEBUG,console,file #控制台输出的相关设置 log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.Threshold=DEBUG log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=[%c]-%m%n #文件输出的相关设置 log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File=./log/log4j.txt log4j.appender.file.MaxFilesize=10mb log4j.appender.file.Threshold=DEBUG log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n #口志输出级别 log4j.logger.org.mybatis=DEBUG log4j.logger.java.dql=DEBUG log4j.logger.java.sq1.statement=DEBUG log4j.logger.java.sq1.ResultSet=DEBUG log4j.logger.java.sq1.PreparedStatement=DEBUG 配置log4j日志实现 <!--在mybatis核心文件中配置 --> <settings> <setting name="logImpl" value="LOG4J"/> </settings>

    5.23、Log4j简单使用

    在要使用Log4j的类中,导入包:import org.apache.log4j.Logger;

    创建日志对象,参数为当前类名

    static Logger logger = Logger.getLogger(BookTypeMapperTest.class);

    日志级别

    级别不同,输出的标签不同,方便筛选 //提示 logger.info("info,进入了log4j"); //调试 logger.debug("debug,进入了log4j"); //紧急 logger.error("error,进入了log4j");

    ​ 日志文件记录内容:

    [INFO][20-11-04][com.lyx.test.BookMapperTest]info进入! [DEBUG][20-11-04][com.lyx.test.BookMapperTest]debug进入 [ERROR][20-11-04][com.lyx.test.BookMapperTest]error进入!

    六、分页查询

    分页的作用:减少数据处理量

    6.2、使用Limit分页查询

    语法: select * from Emp limit staIndex,pageSize; Limit两个属性: staIndex:起止位置pageSize:查询数据的条数如果只传入一个属性,默认起始位置为0
    Processed: 0.032, SQL: 9