• Mybatis学习笔记一


    Mybatis介绍

    MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

    MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。

    Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

    使用jdbc编程问题总结

    1.  数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。如果使用数据库连接池可解决此问题。
    2. Sql语句在代码中硬编码,造成代码不易维护,实际应用中sql变化的可能较大,sql变动需要改变java代码。
    3. 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
    4. 对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。

    Mybatis架构

    1、mybatis配置:

    • SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
    • mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。

    2、通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂

    3、由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。

    4、mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。

    5、Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。

    6、Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

    7、Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

    Mybatis入门程序

     1、pom.xml如下:

    <?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.yyb</groupId>
        <artifactId>mybitis</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <dependencies>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.2.7</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.8</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.11</version>
            </dependency>
    
        </dependencies>
    
        <build>
            <finalName>mybatis</finalName>
            <!--配置jdk版本为1.8-->
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.5.1</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>

    2、创建数据库,准备数据。

    /*
    Navicat MySQL Data Transfer
    
    Source Server         : localhost_3306
    Source Server Version : 50521
    Source Host           : localhost:3306
    Source Database       : mybatis
    
    Target Server Type    : MYSQL
    Target Server Version : 50521
    File Encoding         : 65001
    
    Date: 2015-04-09 16:03:53
    */
    
    SET FOREIGN_KEY_CHECKS=0;
    
    -- ----------------------------
    -- Table structure for `orders`
    -- ----------------------------
    DROP TABLE IF EXISTS `orders`;
    CREATE TABLE `orders` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `user_id` int(11) NOT NULL COMMENT '下单用户id',
      `number` varchar(32) NOT NULL COMMENT '订单号',
      `createtime` datetime NOT NULL COMMENT '创建订单时间',
      `note` varchar(100) DEFAULT NULL COMMENT '备注',
      PRIMARY KEY (`id`),
      KEY `FK_orders_1` (`user_id`),
      CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
    ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of orders
    -- ----------------------------
    INSERT INTO `orders` VALUES ('3', '1', '1000010', '2015-02-04 13:22:35', null);
    INSERT INTO `orders` VALUES ('4', '1', '1000011', '2015-02-03 13:22:41', null);
    INSERT INTO `orders` VALUES ('5', '10', '1000012', '2015-02-12 16:13:23', null);
    
    -- ----------------------------
    -- Table structure for `user`
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `username` varchar(32) NOT NULL COMMENT '用户名称',
      `birthday` date DEFAULT NULL COMMENT '生日',
      `sex` char(1) DEFAULT NULL COMMENT '性别',
      `address` varchar(256) DEFAULT NULL COMMENT '地址',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of user
    -- ----------------------------
    INSERT INTO `user` VALUES ('1', '王五', null, '2', null);
    INSERT INTO `user` VALUES ('10', '张三', '2014-07-10', '1', '北京市');
    INSERT INTO `user` VALUES ('16', '张小明', null, '1', '河南郑州');
    INSERT INTO `user` VALUES ('22', '陈小明', null, '1', '河南郑州');
    INSERT INTO `user` VALUES ('24', '张三丰', null, '1', '河南郑州');
    INSERT INTO `user` VALUES ('25', '陈小明', null, '1', '河南郑州');
    INSERT INTO `user` VALUES ('26', '王五', null, null, null);
    创建表SQL语句

    3、创建pojo

    package cn.itcast.mybatis.po;
    
    import java.io.Serializable;
    import java.util.Date;
    
    public class Orders  implements Serializable{
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
    
        private Integer id;
    
        private Integer userId;
    
        private String number;
    
        private Date createtime;
    
        private String note;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public Integer getUserId() {
            return userId;
        }
    
        public void setUserId(Integer userId) {
            this.userId = userId;
        }
    
        public String getNumber() {
            return number;
        }
    
        public void setNumber(String number) {
            this.number = number == null ? null : number.trim();
        }
    
        public Date getCreatetime() {
            return createtime;
        }
    
        public void setCreatetime(Date createtime) {
            this.createtime = createtime;
        }
    
        public String getNote() {
            return note;
        }
    
        public void setNote(String note) {
            this.note = note == null ? null : note.trim();
        }
    
        
        
    }
    Orders.java
    package cn.itcast.mybatis.po;
    
    import java.io.Serializable;
    import java.util.Date;
    
    public class User implements Serializable {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private Integer id;
        private String username;// 用户姓名
        private String sex;// 性别
        private Date birthday;// 生日
        private String address;// 地址
    
    
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public String getSex() {
            return sex;
        }
        public void setSex(String sex) {
            this.sex = sex;
        }
        public Date getBirthday() {
            return birthday;
        }
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
        public String getAddress() {
            return address;
        }
        public void setAddress(String address) {
            this.address = address;
        }
        @Override
        public String toString() {
            return "User [id=" + id + ", username=" + username + ", sex=" + sex
                    + ", birthday=" + birthday + ", address=" + address + "]";
        }
    
        
        
    
    }
    User.java

    4、在resources下加入log4j.propertiesSqlMapConfig.xml配置文件

    mybatis默认使用log4j作为输出日志信息。log4j.properties配置如下:

    # Global logging configuration
    log4j.rootLogger=DEBUG, stdout
    # Console output...
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
    View Code

    SqlMapConfig.xmlmybatis核心配置文件,配置文件内容为数据源、事务管理。配置如下:

    <?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>
        <!-- 和spring整合后 environments配置将废除 -->
        <environments default="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/mybatis?characterEncoding=utf-8" />
                    <property name="username" value="root" />
                    <property name="password" value="root" />
                </dataSource>
            </environment>
        </environments>
    </configuration>

    5、在resources下创建一个mapper文件夹,添加User.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:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 -->
    <mapper namespace="test">
        <!-- id:statement的id 或者叫做sql的id-->
        <!-- parameterType:声明输入参数的类型 -->
        <!-- resultType:声明输出结果的类型,应该填写pojo的全路径 -->
        <!-- #{}:输入参数的占位符,相当于jdbc的? -->
        <select id="queryUserById" parameterType="int"  resultType="com.yyb.pojo.User">
            SELECT * FROM user WHERE id  = #{id}
        </select>
    </mapper>

    6、添加测试类

    package com.yyb.test;
    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;
    
    
    /**
     * Created by Administrator on 2017/8/15.
     */
    public class Test {
        @org.junit.Test
        public void func1() {
            String path = "SqlMapConfig.xml";
            InputStream resourceAsStream = null;
            try {
                // 1. 加载SqlMapConfig.xml配置文件
                resourceAsStream = Resources.getResourceAsStream(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 2. 创建SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            //3. 创建SqlSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            // 4. 执行SqlSession对象执行查询,获取结果User
            // 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
            Object user = sqlSession.selectOne("test.queryUserById", 1);
    
            // 5. 打印结果
            System.out.println(user);
    
            // 6. 释放资源
            sqlSession.close();
        }
    }

    最终项目结构如下:

    7、测试效果:User [id=1, username=王五, sex=2, birthday=null, address=null]

    实现根据用户名模糊查询用户

     在user.xml中添加以下代码:

    <!-- //根据用户名称模糊查询用户列表
        #{}    select * from user where id = ?    占位符  ? ==  '五'
        ${}    select * from user where username like '%五%'  字符串拼接
         区别主要是单引号的问题  #{}会加单引号  ${value}不会加单引号,名字必须为value
         -->
        <select id="findByUserName" parameterType="String" resultType="com.yyb.pojo.User">
            SELECT * FROM user WHERE username  like '%${value}%'
    --也可以这样,防止SQL注入:
    SELECT * FROM user WHERE username like "%"#{value}"%"
        </select>

    测试代码如下:

        @org.junit.Test
        public void func2() {
            String path = "SqlMapConfig.xml";
            InputStream resourceAsStream = null;
            try {
                // 1. 加载SqlMapConfig.xml配置文件
                resourceAsStream = Resources.getResourceAsStream(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 2. 创建SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            //3. 创建SqlSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            // 4. 执行SqlSession对象执行查询,获取结果User
            // 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
            List<User> users = sqlSession.selectList("test.findByUserName", "五");
    
            // 5. 打印结果
            System.out.println(users);
    
            // 6. 释放资源
            sqlSession.close();
        }

    #{}${}的区别

    #{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。

    ${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。

    parameterType和resultType

    parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。

    resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List中

    selectOne和selectList

    selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常:

    org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)

    selectList可以查询一条或多条记录。

    实现添加用户

     在user.xml中添加如下代码:

     <insert id="addUser" parameterType="com.yyb.pojo.User" >
          INSERT into USER(username,birthday,address,sex) VALUES (#{username},#{birthday},#{address},#{sex})
        </insert>

    测试代码如下;

     @org.junit.Test
        public void func3() {
            String path = "SqlMapConfig.xml";
            InputStream resourceAsStream = null;
            try {
                // 1. 加载SqlMapConfig.xml配置文件
                resourceAsStream = Resources.getResourceAsStream(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 2. 创建SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            //3. 创建SqlSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            // 4. 执行SqlSession对象执行查询,获取结果User
            // 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
            User user=new  User();
            user.setUsername("yyb");
            user.setSex("男");
            user.setBirthday(new Date());
            user.setAddress("cd");
           int i = sqlSession.insert("test.addUser",user);
            sqlSession.commit();
            // 5. 打印结果
            System.out.println(i);
    
            // 6. 释放资源
            sqlSession.close();
        }

    mysql自增主键返回

    查询id的sql:SELECT LAST_INSERT_ID()

    通过修改User.xml映射文件,可以将mysql自增主键返回,如下添加selectKey 标签:

    修改上面的user.xml如下:

     <insert id="addUser" parameterType="com.yyb.pojo.User" >
            <!-- selectKey 标签实现主键返回 -->
            <!-- keyColumn:主键对应的表中的哪一列 -->
            <!-- keyProperty:主键对应的pojo中的哪一个属性 -->
            <!-- order:设置在执行insert语句前执行查询id的sql,该值在执行insert语句之后执行查询id的sql -->
            <!-- resultType:设置返回的id的类型 -->
            <selectKey keyColumn="id" keyProperty="id" order="AFTER" resultType="int">
                SELECT LAST_INSERT_ID()
            </selectKey>
          INSERT into USER(username,birthday,address,sex) VALUES (#{username},#{birthday},#{address},#{sex})
        </insert>

    执行完后,取值即可

    System.out.println(user.getId());

    修改用户

    根据用户id修改用户名,在user.xml中添加如下代码:

        <update id="updateUser" parameterType="com.yyb.pojo.User" >
          UPDATE USER SET username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} WHERE id = #{id}
        </update>

    测试代码如下:

     @org.junit.Test
        public void func4() {
            String path = "SqlMapConfig.xml";
            InputStream resourceAsStream = null;
            try {
                // 1. 加载SqlMapConfig.xml配置文件
                resourceAsStream = Resources.getResourceAsStream(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 2. 创建SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            //3. 创建SqlSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            // 4. 执行SqlSession对象执行查询,获取结果User
            // 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
            User user=new  User();
            user.setId(28);
            user.setUsername("rhr");
            user.setSex("女");
            user.setBirthday(new Date());
            user.setAddress("cd");
            int i = sqlSession.update("test.updateUser",user);
            sqlSession.commit();
            // 5. 打印结果
            System.out.println(i);
            // 6. 释放资源
            sqlSession.close();
        }

    删除用户

    根据用户id删除用户,在user.xml中添加如下代码:

     <delete id="deleteUser" parameterType="Integer" >
            DELETE FROM USER  WHERE  id=#{id}
        </delete>

    测试代码如下:

     @org.junit.Test
        public void func5() {
            String path = "SqlMapConfig.xml";
            InputStream resourceAsStream = null;
            try {
                // 1. 加载SqlMapConfig.xml配置文件
                resourceAsStream = Resources.getResourceAsStream(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 2. 创建SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            //3. 创建SqlSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
    
            // 4. 执行SqlSession对象执行查询,获取结果User
            // 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
            int i = sqlSession.delete("test.deleteUser",28);
            sqlSession.commit();
            // 5. 打印结果
            System.out.println(i);
            // 6. 释放资源
            sqlSession.close();
        }

    Mybatis解决jdbc编程的问题

    1、 数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。

    解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库链接。

    2、 Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。

    解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。

    3、 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。

    解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。

    4、 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。

    解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。

    mybatishibernate不同

    Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。

    Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。

    Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。

    总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。 

    SqlSession的使用范围

    SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。

    SqlSession通过SqlSessionFactory创建。

    SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。

    SqlSessionFactoryBuilder

    SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory创建的。所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

    SqlSessionFactory

    SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。

    SqlSession

    SqlSession是一个面向用户的接口,sqlSession中定义了数据库操作方法。

    每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。

    打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。如下:

    SqlSession session = sqlSessionFactory.openSession();
    
    try {
         // do work
    } finally {
        session.close();
    }

    原始Dao开发中存在以下问题:

    • Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法
    • 调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不利于开发维护。

    Mapper动态代理方式

    开发规范

    Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

    Mapper接口开发需要遵循以下规范:

    • Mapper.xml文件中的namespace与mapper接口的类路径相同。
    • Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
    • Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
    • Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

     比如:

    public interface UserMapper {
    
        
        //遵循四个原则
        //接口 方法名  == User.xml 中 id 名
        //返回值类型  与  Mapper.xml文件中返回值类型要一致
        //方法的入参类型 与Mapper.xml中入参的类型要一致
        //命名空间 绑定此接口
        public User findUserById(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">
    <!-- 写Sql语句   -->
    <mapper namespace="com.itheima.mybatis.mapper.UserMapper">
        <!-- 通过ID查询一个用户 -->
        <select id="findUserById" parameterType="Integer" resultType="User">
            select * from user where id = #{id}
        </select>
    </mapper>

    测试代码如下:

        @Test
        public void testMapper() throws Exception {
            //加载核心配置文件
            String resource = "sqlMapConfig.xml";
            InputStream in = Resources.getResourceAsStream(resource);
            //创建SqlSessionFactory
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
            //创建SqlSession
            SqlSession sqlSession = sqlSessionFactory.openSession();
            
            //SqlSEssion帮我生成一个实现类  (给接口)
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            
            
            User user = userMapper.findUserById(10);
            System.out.println(user);
        }

    selectOne和selectList

    动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。

    namespace

    mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入参数可以使用pojo包装对象或map对象,保证dao的通用性。

    SqlMapConfig.xml配置文件

    SqlMapConfig.xml中配置的内容和顺序如下:

    1. properties(属性)
    2. settings(全局配置参数)
    3. typeAliases(类型别名)
    4. typeHandlers(类型处理器)
    5. objectFactory(对象工厂)
    6. plugins(插件)
    7. environments(环境集合属性对象)
    8. environment(环境子属性对象)
    9. transactionManager(事务管理)
    10. dataSource(数据源)
    11. mappers(映射器)

    properties(属性)

    SqlMapConfig.xml可以引用java属性文件中的配置信息,如下:

    db.properties配置文件内容如下:

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
    jdbc.username=root
    jdbc.password=root

    SqlMapConfig.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>
        <!-- 是用resource属性加载外部配置文件 -->
        <properties resource="db.properties">
            <!-- 在properties内部用property定义属性 -->
            <!-- 如果外部配置文件有该属性,则内部定义属性被外部属性覆盖 -->
            <property name="jdbc.username" value="root123" />
            <property name="jdbc.password" value="root123" />
        </properties>
    
        <!-- 和spring整合后 environments配置将废除 -->
        <environments default="development">
            <environment id="development">
                <!-- 使用jdbc事务管理 -->
                <transactionManager type="JDBC" />
                <!-- 数据库连接池 -->
                <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="sqlmap/User.xml" />
            <mapper resource="mapper/UserMapper.xml" />
        </mappers>
    </configuration>

     typeAliases(类型别名)

    默认支持别名如下:

    别名

    映射的类型

    _byte

    byte

    _long

    long

    _short

    short

    _int

    int

    _integer

    int

    _double

    double

    _float

    float

    _boolean

    boolean

    string

    String

    byte

    Byte

    long

    Long

    short

    Short

    int

    Integer

    integer

    Integer

    double

    Double

    float

    Float

    boolean

    Boolean

    date

    Date

    decimal

    BigDecimal

    bigdecimal

    BigDecimal

    map

    Map

    自定义别名:

    SqlMapConfig.xml中配置如下:

        <typeAliases>
            <!-- 单个别名定义 -->
            <typeAlias alias="user" type="cn.itcast.mybatis.pojo.User" />
            <!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
            <package name="cn.itcast.mybatis.pojo" />
            <package name="其它包" />
        </typeAliases>

    在mapper.xml配置文件中,就可以使用设置的别名了。别名大小写不敏感。

    mappers(映射器)

    Mapper配置的几种方法:

    1、<mapper resource=" " />,使用相对于类路径的资源(现在的使用方式)。如:<mapper resource="sqlmap/User.xml" />

    2、<mapper class=" " />,使用mapper接口类路径。如:<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>。注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中(使用maven的话,要把xml放到resource目录下,路径要和mapper对应)。

    3、<package name=""/>,注册指定包下的所有mapper接口。如:<package name="cn.itcast.mybatis.mapper"/>。注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中(使用maven的话,要把xml放到resource目录下,路径要和mapper对应)。

  • 相关阅读:
    今日确定开源近两年来的EA程序
    升级了NinjaLoveFish Excel量化表格
    到家第一件事就是脱衣服
    对挑选完成的股票,进行批量建仓
    lua 学习之错误处理
    lua 学习之编译
    Lambda 演算入门
    lua学习之深入函数第二篇
    lua学习之深入函数第一篇
    lua学习之复习汇总篇
  • 原文地址:https://www.cnblogs.com/ginb/p/7366805.html
Copyright © 2020-2023  润新知