zoukankan      html  css  js  c++  java
  • 框架MyBatis

     ByBatis

    MyBatis是Apache的一个开源项目iBatis,iBatis3.x 正式更名为MyBatis ,代码于2013年11月迁移到Github。它是一个基于Java的持久层框架(连数据库用的)。 iBatis提供的持久层框架包括SQL Maps和Data Access Objects(DAO)

    https://github.com/mybatis/mybatis-3/ 

    MyBatis简介(半自动化)

    1) MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架

    2) MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集

    3) MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录

    4) 半自动ORM(Object Relation Mapping`)框架

    SSH(全自动的,连接数据库黑箱操作,sql语句都不用写) 、SSM

    1、开发环境的准备

    1) 创建Maven版的Java工程

    2) 加入MyBatis框架的jar包、Mysql驱动包、log4j(可以看到发送的sql语句)的jar包的依赖

    pom.xml

    <!-- MyBatis -->
          <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.2</version>
          </dependency>
          
          <!-- MySql -->
          <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.37</version>
          </dependency>
          
          <!-- log4j -->
          <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
          </dependency>
    View Code

    3) 导入log4j 的配置文件(可以看到传的参数,查询的结果)

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
     
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
     
     <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
       <param name="Encoding" value="UTF-8" />
       <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) 
    " />
       </layout>
     </appender>
     <logger name="java.sql">
       <level value="debug" />
     </logger>
     <logger name="org.apache.ibatis">
       <level value="info" />
     </logger>
     <root>
       <level value="debug" />
       <appender-ref ref="STDOUT" />
     </root>
    </log4j:configuration>
    View Code

    2、创建测试表; 在MySQL中创建数据库和数据表

    3、创建javaBean

    4、创建MyBatis的全局配置文件( 参考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">
            <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" />
                    <property name="username" value="root" />
                    <property name="password" value="root" />
                </dataSource>
            </environment>
        </environments>
        <!-- 引入SQL映射文件,Mapper映射文件 -->
        <mappers>
            <mapper resource="com/atguigu/mybatis/mapper/EmployeeMapper.xml" />
        </mappers>
    </configuration>
    View Code

    5、创建Mapper接口(增删改查等方法,就是之前写的UserDAO接口)

    之前是要写一个接口的实现类,现在不需要,MyBatis自动创建代理实现类,不用写实现类了,只需写sql语句,写到一个xml的映射文件(它来生成代理实现类)里边。

    6、创建Mybatis的sql映射文件(参考官网)

    <?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 namespace="com.atguigu.mybatis.mapper.EmployeeMapper">
        <!-- 
            id属性:指定Mapper接口中方法的方法名
            resultType属性:指定方法返回值类型的全类名,方法的返回值返回的Employee对象
         -->
        <select id="getEmployeeById" resultType="com.atguigu.mybatis.entities.Employee">
            select id,last_name lastName,email,salary,dept_id deptId   -->>查询的时候起别名是为了能够找到它们的get/set方法,造好对象要调get/set方法,如果类里边没有就赋不上值from employees where id = #{ id }   取填充占位符,根据传入的参数取占位符的值 
      </select> 添加、插入的时候不起别名。 </mapper>

     这个映射文件需要在MyBatis全局配置文件里边注册,即引入sql映射文件--Mapper映射文件

    <!-- 引入SQL映射文件,Mapper映射文件 -->
        <mappers>
            <mapper resource="com/atguigu/mybatis/mapper/EmployeeMapper.xml" />
        </mappers>

    7、测试

    注意导入的包不要导错了

    import java.io.IOException;
    import java.io.InputStream;
    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 org.junit.jupiter.api.Test;
      @Test
        void testGetEmployeeById() throws IOException {
            // 1.创建SqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);  //读成一个流
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //把流传进去;
            //2.获取SqlSession对象,相当于JDBC中的Connection
            SqlSession session = sqlSessionFactory.openSession(); //得到连接
            try {
                //3.获取Mapper接口的代理实现类 ;虽然是接口类型,但MyBatis创建了一个实现类(代理实现类) proxy.$Proxy8
            
    EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);
    //4.调用EmployeeMapper中获取Employee的方法 ;调接口里边的方法。 Employee employee = employeeMapper.getEmployeeById(1); System.out.println(employee); } finally { //5.关闭SqlSession,关闭下这个连接 session.close(); } }

    两个绑定

    1) Mapper接口与Mapper映射文件的绑定

    在Mppper映射文件中的<mapper>标签中的namespace中必须指定Mapper接口

    的全类名

    2)  Mapper映射文件中的增删改查标签的id必须指定成Mapper接口中的方法名

    用接口的好处:赋实现类的时候不同的实现类都可以赋值给这个类型,为了解耦,以后只在一个类里边写一个接口类型,不同的实现类都可以赋值给它。

    导入提示:能写哪些xml都在这个文件里边 http://mybatis.org/dtd/mybatis-3-config.dtd,把它导入进来。

    MyBatis 高级映射

    接口

    package com.atguigu.mybatis.mapper;
    
    import java.util.List;
    import java.util.Map;
    
    import org.apache.ibatis.annotations.Param;
    
    import com.atguigu.mybatis.entitis.Employee;
    
    public interface EmployeeMapper {
        // select获取一个员工的方法
        Employee getEmployeeById(Integer id);
    
        // select多行数据返回对象的集合
        List<Employee> getAllEmployees();
    
        // insert,添加员工;可以写void没有返回值的
        public Integer insertEmployee(Employee employee);
    
        // update,修改;可以写void
        public Boolean updateEmployee(Employee employee);
    
        // delete,删除
        public void deleteEmployeeById(Integer id);
    
        Employee getEmployeeByLastNameAndEmail(@Param("lastName") String lastName, @Param("email") String email);
    
        Employee getEmployeeByMap(Map<String, Object> map);
    
    }

     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 namespace="com.atguigu.mybatis.mapper.EmployeeMapper">
        <!-- 
            1.根据id查找一个员工;id属性:指定Mapper接口中方法的方法名;resultType属性:指定方法返回值类型的全类名
         -->
        <select id="getEmployeeById" resultType="com.atguigu.mybatis.entitis.Employee">
            select id,last_name lastName,email,salary,dept_id deptId 
            from employees where id = #{id}  这个参数id可以随便写。
        </select>
        
        <!--2.查找出所有的员工信息,如果返回值是List, 这里resultType不是List类型,是List里边泛型的类型,它查询出来是放到List里边的封装成Employee对象  -->
        <select id="getAllEmployees" resultType="com.atguigu.mybatis.entitis.Employee">
            select id, last_name lastName, email, salary, dept_id deptId from 
            employees  
        </select>
        
        
        <!-- 3.添加员工,传入的参数是Employee类型,paramterType可写可不写
           parameterType属性:设置Mapper接口中的方法的入参的类型,该属性可以省略不写 -->
    <insert id="insertEmployee" parameterType="com.atguigu.mybatis.entitis.Employee"> insert into employees(last_name, email, salary, dept_id) values
    </insert> <!-- 4.更新修改员工信息 --> <update id="updateEmployee" > update employees set last_name = #{lastName}, email = #{email}, salary = #{salary}, dept_id = #{deptId} where id = #{id} </update> <!-- 5.删除员工 --> <delete id="deleteEmployeeById"> delete from employees where id = #{id} </delete> <!-- 根据用户名和邮箱查询查询一个用户 --> <select id="getEmployeeByLastNameAndEmail" resultType="com.atguigu.mybatis.entitis.Employee"> select id, last_name lastName, email, salary, dept_id deptId from employees where last_name = </select> 要在接口的方法形参里边加上注解在这里就可以使用lastName和email了,也可以使用param1和param2,但不能用arg0/arg1。 <!-- 根据传入的Map查询一个用户 --> <select id="getEmployeeByMap" resultType="com.atguigu.mybatis.entitis.Employee"> select id, last_name lastName, email, salary, dept_id deptId from employees where last_name = #{ln} and email = #{el} </select> </mapper>
    package com.atguigu.mybatis.test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.HashMap;
    import java.util.List;
    
    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 org.junit.Test;
    
    import com.atguigu.mybatis.entitis.Employee;
    import com.atguigu.mybatis.mapper.EmployeeMapper;
    
    public class MyBatisTest {
        //获取SqlSessionFactory的方法
        // 创建SqlSessionFactory对象
        public SqlSessionFactory getSessionFactory() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        return sqlSessionFactory;
        
        
        }
        //1.获取一个员工
        @Test
        public void testGetEmployeeById() throws IOException {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //2.获取SqlSession对象,相当于JDBC中的Connection
            SqlSession session = sqlSessionFactory.openSession();
            try {
                //3.获取Mapper接口的代理实现类
                EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);
                //4.调用EmployeeMapper中获取Employee的方法
                Employee employee = employeeMapper.getEmployeeById(1);
                System.out.println(employee);
            } finally {
                //5.关闭SqlSession
                session.close();
            }
        }
        //2.获取所有的员工信息;
        @Test
        public void testGetAllEmployees() throws IOException {
            //①获取SqlSessionFactory对象
            SqlSessionFactory sessionFactory = getSessionFactory();
            //②获取SqlSession对象
            SqlSession sqlSession = sessionFactory.openSession();
            //③获取Mapper接口对象
            EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
            //调用EmployeeMapper中获取所有员工的方法;
            List<Employee> allEmployees = employeeMapper.getAllEmployees();
            for (Employee employee : allEmployees) {
                System.out.println(employee);
            }
            //关闭
            sqlSession.close();
        
        }
        
        
        //3.测试添加员工 
        @Test
        public void testInsertEmployee() throws IOException {
            //①获取SqlSessionFactory对象
            SqlSessionFactory sessionFactory = getSessionFactory();
            //②获取SqlSession
            SqlSession sqlSession = sessionFactory.openSession();
            //③获取Mapper接口对象
            EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
            //创建Employee对象;
            Employee employee = new Employee(null, "kris12", "kris@qq.com", 20000.0, 2);
            //④调用EmployeeMapper中添加员工的方法
            //employeeMapper.insertEmployee(employee);
        
            //4.更新修改员工
            //employeeMapper.updateEmployee(new Employee(7, "smile", "smile@123.com", 10000,  3));
            
            
            //5.删除员工信息
            employeeMapper.deleteEmployeeById(7);
            
            sqlSession.commit(); //要记得提交事务;
            sqlSession.close();
        }
    
        
        //根据用户名和邮箱获取一个员工
        @Test
        public void testGetEmployeeByLastNameAndEmail() throws IOException {
            SqlSessionFactory sqlSessionFactory = getSessionFactory();
        
            SqlSession sqlSession = sqlSessionFactory.openSession();
            
            //获得Mapper对象
            EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
            Employee employee = employeeMapper.getEmployeeByLastNameAndEmail("kris", "kris@qq.com");
            
            System.out.println(employee);
            sqlSession.close();
        }
        
        //根据传入的Map查询一个用户
        @Test
        public void testGetEmployeeByMap() throws IOException {
            SqlSessionFactory sessionFactory = getSessionFactory();
            
            SqlSession sqlSession = sessionFactory.openSession();
            
            EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
            //调用EmployeeMapper中根据Map获取用户的方法
            HashMap<String, Object> hashMap = new HashMap<>();
            hashMap.put("ln", "kris");
            hashMap.put("el", "kris@qq.com");
            Employee employee = employeeMapper.getEmployeeByMap(hashMap);
            System.out.println(employee);
            
            sqlSession.close();
        
        }
    
    }
    MyBatis对Mapper接口中方法的入参的处理:
                1.单个参数
                    MyBatis不做任何处理,此时填充占位符时取值的key可以任意指定
                  例如:#{任意指定}
                2.多个参数
                    MyBatis会将多个参数封装到一个Map中,向Map中放值时的key是arg0、arg1...或者param1、param2...
                    此时填充占位符时取值的key就是arg0、arg1...或者param1、param2...
                 例如:last_name = #{arg0}/#{param1} and email = #{arg1}/#{param2}
                     我们也可以通过在Mapper接口的方法入参的前面添加@Param注解的方式来指定改key,此时填充占位符时取值的key
                     就是@Param注解中指定的值
                3.POJO
                    如果传入的多个参数可以封装成POJO对象,那么可以直接传入POJO对象,此时填充占位符时取值的key
                    就是POJO的属性名
                例如:last_name = #{POJO的属性名}
                4.Map
                    如果传入的多个参数不可以封装成POJO对象,可以将多个参数放到Map中,然后传入一个Map,
                    此时填充占位符时取值的key就是向Map中放值时指定的key
                

     源码见下:

     public Object getNamedParams(Object[] args) {
        final int paramCount = names.size();
        if (args == null || paramCount == 0) {
          return null;
        } else if (!hasParamAnnotation && paramCount == 1) {
          return args[names.firstKey()];
        } else {
          final Map<String, Object> param = new ParamMap<Object>();
          int i = 0;
          for (Map.Entry<Integer, String> entry : names.entrySet()) {
            param.put(entry.getValue(), args[entry.getKey()]);
            // add generic param names (param1, param2, ...)
            final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
            // ensure not to overwrite parameter named with @Param
            if (!names.containsValue(genericParamName)) {
              param.put(genericParamName, args[entry.getKey()]);
            }
            i++;
          }
          return param;
        }
      }
    View Code

    resultMap自定义映射

    1)  自定义resultMap,实现高级结果集映射

    2) id :用于完成主键值的映射

    3) result :用于完成普通列的映射

    4) association :一个复杂的类型关联;许多结果将包成这种类型

       POJO中的属性可能会是一个对象,我们可以使用联合查询,并以级联属性的方式封装对象.使用association标签定义对象的封装规则

    5)  collection : 复杂类型的集

      POJO中的属性可能会是一个集合对象,我们可以使用联合查询,并以级联属性的方式封装对象.使用collection标签定义对象的封装规则

    接口

      Employee getEmployeeByMap(Map<String, Object> map);
    
        Employee2 getEmployeeByIdContainsDept(Integer id);
    <!-- 8在查询员工的同时把员工的部门信息也查询出来;u=自定义高级映射,resultMap属性:指定高级结果集的id属性值 -->
        <select id="getEmployeeByIdContainsDept" resultMap="myMap">
    
            SELECT employees.*, d.id AS d_id, d.name AS d_name
            FROM employees LEFT
            JOIN departments AS d
            ON employees.dept_id = d.id
            WHERE employees.eid = #{id};
        </select>
        <!-- type属性:设置要映射的POJO的全类名;  id属性:设置一个唯一的标示以便被引用 -->
        <resultMap type="com.atguigu.mybatis.entitis.Employee2" id="myMap">
            <!-- 先映射主键;column属性:指定数据库中的列名,property属性:指定POJO的属性名 -->
            <id column="eid" property="id" />
            <!-- 再映射其他列 -->
            <result column="last_name" property="lastName" />
            <result column="email" property="email" />
            <result column="salary" property="salary" />
            
            <!-- 方式一: 通过给级联属性赋值映射部门信息;没有关联之前dept=null -->
            <!-- <result column="d_id" property="dept.id" />
            <result column="d_name" property="dept.name" /> -->
    
        <!-- 方式二:通过association标签实现联合查询 
                property属性:指定要映射的属性的属性名
                javaType属性:指定要映射的属性的类型
            -->
            <association property="dept" javaType="com.atguigu.mybatis.entitis.Department">
                <id column="d_id" property="id"/> <!-- 映射id -->
                <result column="d_name" property="name"/> <!-- 映射其他列 -->
            </association>
        </resultMap>

     

    public interface DepartmentMapper {
        Department getDepartmentByIdContainsEmps(Integer id);
    }
    <?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 namespace="com.atguigu.mybatis.mapper.DepartmentMapper">
        
        <select id="getDepartmentByIdContainsEmps" resultMap="myMap">
            SELECT d.id , d.name ,e.*
            FROM departments d
            LEFT JOIN employees e
            ON d.id = e.dept_id
            WHERE d.id = #{id}
            
        </select>
        <resultMap type="com.atguigu.mybatis.entitis.Department" id="myMap">
            <!-- 先映射主键;column属性:指定数据库中的列名,property属性:指定POJO的属性名 -->
            <id column="id" property="id" />
            <result column="name" property="name"/>
            
            <collection property="emps" ofType="com.atguigu.mybatis.entitis.Employee2">
                <id column="eid" property="id"/>
                <result column="last_name" property="lastName"/>
                <result column="email" property="email"/>
                <result column="salary" property="salary"/>
            </collection>
            
        </resultMap>
    </mapper>

    mybatic-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>
    
        <settings>
            <setting name="mapUnderscoreToCamelCase" value="true"/>
        </settings>
    
        <!-- 数据库连接环境的配置 -->
        <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" />
                    <property name="username" value="root" />
                    <property name="password" value="123456" />
                </dataSource>
                
            </environment>
        </environments>
        <!-- 引入SQL映射文件,Mapper映射文件 -->
        <mappers>
            <mapper resource="com/atguigu/mybatis/mapper/EmployeeMapper.xml" />
            <mapper resource="com/atguigu/mybatis/mapper/DepartmentMapper.xml"/>
        </mappers>
    </configuration>
    View Code

    注:

    MyBatis配置文件自动提示的配置:

    MyBatis的全局配置文件和Mapper映射文件的xml文件的标签写的时候有提示;注意它两个文件的对应;

    http://mybatis.org/dtd/mybatis-3-mapper.dtd

    http://mybatis.org/dtd/mybatis-3-config.dtd

  • 相关阅读:
    年度回忆录(?——2011.01)
    我在学英语
    技能冷却
    抗锯齿
    在cocos2dx 2.x FPS 等参数
    手指效果
    cocos2dx 简单OpenGL 画图
    cocos2dx tile map瓦片地图的黑线及地图抖动解决方案
    C++操作SQLite数据库
    精灵点击移动
  • 原文地址:https://www.cnblogs.com/shengyang17/p/10199328.html
Copyright © 2011-2022 走看看