MyBatis框架

第一章 认识框架

1.1 什么是框架 frame

框架就是一个架子,表演节目,舞台已经搭建好,表演什么节目,看自己的需求了。

框架是一个半成品,对于Java语言来说,框架就是封装了别人的代码。在框架的基础上我们在进一步开发,拿来主义。

解决的是技术整合问题。软件开发环境和规模都很大,不可能任何一个项目的代码都从零开始,此时就需要一个非常优秀的框架把基础技术整合完毕,我们在他的基础上进一步开发。提高性能,易扩展,易维护,最终提高整个团队的开发效率。

img002.png

1.2 如何使用框架

企业级大型项目开发,避免大炮打蚊子。

Java的框架是具有一些共性

  • 导入jar包
  • 框架运行细节定义,也就是编写配置文件(xml)
  • 调用框架中的api

1.3 原生JDBC案例的问题

  1. public class UserDaoImpl implements UserDao {
  2. private String driverClass = "com.mysql.jdbc.Driver";
  3. private String url="jdbc:mysql://localhost:3306/test";
  4. private String username="root";
  5. private String password="root";
  6. @Override
  7. public List<User> queryUserList()throws Exception {
  8. List<User> list = new ArrayList<User>();
  9. Class.forName(driverClass);
  10. Connection conn = DriverManager.getConnection(url,username,password);
  11. String sql = "select * from user where id=? and name = ?";
  12. PreparedStatement pst = conn.prepareStatement(sql);
  13. pst.setObject(1,1);
  14. pst.setObject(2,"a");
  15. ResultSet rs = pst.executeQuery();
  16. User user = null;
  17. while (rs.next()){
  18. user = new User();
  19. user.setId(rs.getInt("id"));
  20. user.setUsername(rs.getString("username"));
  21. user.setSex(rs.getString("sex"));
  22. user.setBirthday(rs.getDate("birthday"));
  23. user.setAddress(rs.getString("address"));
  24. list.add(user);
  25. }
  26. rs.close();
  27. pst.close();
  28. conn.close();
  29. return list;
  30. }
  31. }
  • 频繁连接,释放数据库资源,降低系统性能
  • SQL语句硬编码,难以维护
  • 参数和占位符对应问题
  • 结果集解析复杂,列名硬编码

1.4 MyBatis框架介绍

img001.png

  • Mybatis原本是Apache软件基金会的一个开源项目叫做iBatis,2010年这个项目由Apache迁移到了google code管理才改名为Mybatis,2013年又迁移到了GitHub。
  • Mybatis是一个优秀的持久层框架(Dao层框架),它是对JDBC的封装,使得开发者只需要关注Sql语句(业务)本身即可,无需开发者处理加载驱动、获取连接、创建Statement等繁琐的过程。
  • Mybatis最大的特点是把Sql语句写在XML配置文件当中。而且Mybatis执行完Sql语句之后可以以对象形式返回(POJO/POJO集合等)。
  • Mybatis是一个实现了ORM思想的持久层框架。
  • ORM:Object/Relation Mapping 对象/关系映射。
  • ORM思想:将数据库中的关系数据表映射为JAVA中的对象,把对数据表的操作转换为对对象的操作,实现面向对象编程。因此ORM的目的是使得开发人员以面向对象的思想来操作数据库。
    比如:原来insert使用的是insert into…,如果使用实现了ORM思想的持久层框架,就可以在Java程序中直接调用api,比如insert(User),达到操作对象即操作数据库的效果。Hibernate框架是一个全自动的ORM持久层框架,只需要编写POJO,在xml中定义好Pojo属性和数据表字段的映射/对应关系,就可以在java中实现类似 insert(User)的操作。Sql语句都不用写。但是因为性能等问题,市场占有率越来越低
    Mybatis框架是一个半自动的ORM持久层框架,也可以在Java中实现类似 insert(User)的操作最终操作数据库,但是需要我们自己写Sql语句。Mybatis是目前比较流行的Dao层框架。

第二章 MyBatista框架快速入门

1.1准备测试数据

  1. CREATE DATABASE `mybatis-example`;
  2. USE `mybatis-example`;
  3. CREATE TABLE `t_emp`(
  4. emp_id INT AUTO_INCREMENT,
  5. emp_name VARCHAR(100),
  6. emp_salary DOUBLE,
  7. PRIMARY KEY(emp_id)
  8. );
  9. INSERT INTO `t_emp`(emp_name,emp_salary) VALUES("tom",200.33);

1.2 创建JavaSE项目

导入MyBatis框架坐标

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.5</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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!--
                配置一个xml文件,存储的SQL语句
                resource 配置的是存储SQL语句的文件路径和文件名
        -->
        <mapper resource="empMapper.xml"/>
    </mappers>
</configuration>

添加SQL语句配置文件 employeeMapper.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">
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
     <select id="selectEmployee" resultType="com.atguigu.pojo.Employee">
        <!-- select 标签体文本,就是SQL语句-->
        select emp_id empId ,emp_name empName ,emp_salary empSalary from t_emp
    </select>
</mapper>

1.3 MyBatis框架核心API介绍

  • SqlSessionFactoryBuilder类
    • 作用1:读取配置文件
    • 作用2:创建SqlSessionFactory接口对象
    • 方法:build(输入流) 返回SqlSessionFactory接口对象
  • SqlSessionFactory接口
    • 作用:创建SqlSession接口对象
    • 方法:openSession() 返回SqlSession接口对象
  • SqlSession接口
    • 作用1: 执行SQL语句
    • 作用2 :事务控制

1.4 MyBatis框架实现数据表查询

    /**
     * MyBatis框架快速入门
     * 需求:查询数据表t_emp,所有数据
     * 查询结果List集合
     *
     * 实现步骤:
     *  1: 创建输入流,绑定配置文件mybatis-config.xml (主配置文件)
     *  2: 创建对象, SqlSessionFactoryBuilder
     *  3: SqlSessionFactoryBuilder对象的方法build(传递输入流),build方法读取配置文件
     *     build方法返回对象: SqlSessionFactory对象
     *  4:SqlSessionFactory对象的方法 openSession() 打开会话对象(连接数据库)
     *    openSession()方法,返回SqlSession对象 (等同于Connection)
     *  5: SqlSession对象的方法执行SQL语句,返回查询结果集
     *  6: 释放资源
     */
    @Test
    public void queryEmpByList(){
        //1: 创建输入流,绑定配置文件mybatis-config.xml (主配置文件)
        InputStream in =
                MainTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
        //2: 创建对象, SqlSessionFactoryBuilder
        //对象作用是一个工厂,读取配置文件,创建另一个对象SqlSessionFactory
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //3: SqlSessionFactoryBuilder对象的方法build(传递输入流),build方法读取配置文件
        //build方法返回对象: SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
        //4:SqlSessionFactory对象的方法 openSession() 打开会话对象(连接数据库)
        //     *    openSession()方法,返回SqlSession对象 (等同于Connection)
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 5: SqlSession对象的方法执行SQL语句,返回查询结果集
        //SqlSession对象的方法,执行SQL语句
        /**
         *  selectList() 执行SQL语句
         *  参数:String:配置文件中的SQL语句
         *    配置文件的 namespace属性+ .  + 查询语句的id属性, 确定唯一性SQL语句
         *  返回值: List
         */
        List<Employee> employeeList = sqlSession.selectList("employeeMapper.selectEmployee");
        //对集合,安全性判断
        if ( employeeList != null && employeeList.size() > 0 ){
            for (Employee employee : employeeList){
                System.out.println(employee);
            }
        }
        //6: 释放资源
        sqlSession.close();
    }

1.5 添加MyBatis执行日志

导入日志依赖jar包

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

日志配置文件

#log4j日志级别如下:
#A:off     最高等级,用于关闭所有日志记录。
#B:fatal   指出每个严重的错误事件将会导致应用程序的退出。
#C:error   指出虽然发生错误事件,但仍然不影响系统的继续运行。
#D:warn    表明会出现潜在的错误情形。
#E:info    一般和在粗粒度级别上,强调应用程序的运行全程。
#F:debug   一般用于细粒度级别上,对调试应用程序非常有帮助。
#G:all     最低等级,用于打开所有日志记录。

#但log4j只建议使用4个级别,优先级从高到低分别是:
#error>warn>info>debug

log4j.rootLogger =debug,systemOut,logFile

#输出到控制台
log4j.appender.systemOut = org.apache.log4j.ConsoleAppender
log4j.appender.systemOut.layout = org.apache.log4j.PatternLayout
log4j.appender.systemOut.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n
log4j.appender.systemOut.Target = System.out

#输出到文件
log4j.appender.logFile = org.apache.log4j.FileAppender
log4j.appender.logFile.layout = org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n
log4j.appender.logFile.File = E:/log/log4j.log
log4j.appender.logFile.Encoding = UTF-8

#将日志输记录到MySQL数据库
#log4j.appender.logDB = org.apache.log4j.jdbc.JDBCAppender
#log4j.appender.logDB.layout = org.apache.log4j.PatternLayout
#log4j.appender.logDB.Driver = com.mysql.jdbc.Driver
#log4j.appender.logDB.URL = jdbc:mysql://localhost:3306/log4j?characterEncoding=utf-8
#log4j.appender.logDB.User = root
#log4j.appender.logDB.Password = root
#log4j.appender.logDB.Sql = INSERT INTO t_log4j(project_name,create_date,level,category,file_name,thread_name,line,all_category,message)values('mybatis','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','%t','%L','%l','%m')

#若出现问题:Log4j: ERROR Failed to load driver, java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
#解决方法:将log4j.properties 中每行后面的空格都删除就解决了.

1.6 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>
    <!--
        environments  运行环境,多个
         default="development" 默认环境  default 选择器作用
     -->
    <environments default="development">
        <!--
          environment 一个运行环境
          id="development"   id 唯一性
        -->
        <environment id="development">
            <!--
                transactionManager : 配置事务管理器
                什么时候需要事务:新增,删除,修改,同时执行多个
                type="JDBC" : 使用的事务管理器,是默认是的原始JDBC的事务管理器
                type="MANAGERMENT"  事务管理交给第三方框架
            -->
            <transactionManager type="JDBC"/>
            <!--
                dataSource : 配置数据库的连接池
                type="POOLED" ,使用MyBatis自带的连接池
                type="UNPOOLED" ,不使用MyBatis自带的连接池,连接池使用德鲁伊+Spring
            -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>

        <!-- 配置运行环境,测试环境-->
        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-example2"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>


        <!-- 配置运行环境,真实环境-->
        <environment id="runtime">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-example3"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!--
      mappers 配置多个SQL语句的映射文件
    -->
    <mappers>
        <!--
                配置一个xml文件,存储的SQL语句
                resource 配置的是存储SQL语句的文件路径和文件名
        -->
        <mapper resource="empMapper.xml"/>
    </mappers>

</configuration>

第三章 MyBatis框架实现数据CRUD

1.1 根据ID查询用户

<select id="selectEmployeeById" parameterType = "int" resultType="com.atguigu.mybatis.entity.Employee">
select emp_id ,emp_name ,emp_salary  from t_emp where emp_id = #{id}
</select>
public void queryUserById() throws IOException {
    InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory sqlSessionFactory = builder.build(inputStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    Employee emp = sqlSession.selectOne("com.atguigu.mybatis.dao.EmployeeMapper.selectEmployeeById",2);
    System.out.println(emp);
    sqlSession.close();
}

1.2 SQL语句中的参数传递

  • SQL语句中的参数
    • 固定语法,使用${}方式获取参数
    • 基本数据类型及包装类,参数名字任意
    • 底层实现,将SQL语句中的参数编译为?占位符
    • 底层使用高效安全的PreparedStatement实现
    • 能用#不用$
    • 使用#的原理是?占位符,而$的原理为直接字符串拼接方式
    • $使用在参数传入数据库对象的时候,例如表名,列名字等 (select XX from XX order by 列名)

1.3 根据用户名模糊查询

<select id="selectEmployeeByName" parameterType = "string" resultType="com.atguigu.mybatis.entity.Employee">
select emp_id ,emp_name ,emp_salary  from t_emp where emp_id like #{emp_name}
</select>
public void queryEmployeeByName() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    List<User> list = sqlSession.selectList("com.atguigu.mybatis.dao.EmployeeMapper.selectEmployeeByName","'%王%'");
    for(User user : list){
        System.out.println(user);
    }
    sqlSession.close();
}

1.4 新增用户数据

<insert id="insertEmployee" parameterType = "com.atguigu.mybatis.entity.Employee">
    insert into t_emp values(#{empId},#{empName},${empSalary})
</insert>
public void insertEmployee() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    Employee employee = new Employee();
    employee.setEmpId(null);
    employee.setEmpName("testName");
    employee.setEmpSalary(5000D);
    int row = sqlSession.insert("com.atguigu.mybatis.dao.EmployeeMapper.insertEmployee",employee);
    sqlSession.commit();
    sqlSession.close();
}

1.5 获取新增的主键值

1.5.1 数据表主键为自动增长的情况

<insert id="insertEmployee" parameterType = "com.atguigu.pojo.Employee" useGeneratedKeys="true" keyProperty="empId">
     insert into t_emp values(#{empId},#{empName},${empSalary})
</insert>
  • MyBatis框架提供了insert标签的属性:
    • useGeneratedKeys:是否使用自动增长主键
    • keyProperty:获取自动增长的主键值,储存在Employee对象的哪个字段中

1.5.2 数据表主键不是自动增长

对于不支持自增型主键的数据库(例如 Oracle),则可以使用 selectKey 子元素:selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用。

<insert id="insertEmployee" 
        parameterType="com.atguigu.mybatis.beans.Employee"  
            databaseId="oracle">
        <selectKey order="AFTER" keyProperty="id" 
                                         resultType="integer">
            select 表名_seq.currval from dual 
        </selectKey>    
    insert into orcl_employee(id,last_name,email,gender) values(employee_seq.nextval,#{lastName},#{email},#{gender})
</insert>

1.6 更新用户数据

1.7 删除用户数据