zoukankan      html  css  js  c++  java
  • 20160522--20160526----mybatis入门基础

    一、基础知识:

     1.对原生态jdbc程序(单独使用jdbc开发)问题总结

     2.mybatis框架原理 (掌握)

     3.mybatis入门程序

     4.用户的增、删、改、查

     5.SqlMapConfig.xml

     6.输入映射

     7.输出映射

     8.动态sql

    1.对原生态jdbc程序中问题总结

    1.1 环境

    java环境:jdk1.8.0_20

    eclipse:luna

    mysql5.1

    1.2   创建mysql数据

    sql脚本:

    /*
    SQLyog v10.2 
    MySQL - 5.1.72-community : Database - mybatis
    *********************************************************************
    */
    
    
    /*!40101 SET NAMES utf8 */;
    
    /*!40101 SET SQL_MODE=''*/;
    
    /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
    /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
    /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
    /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
    /*Table structure for table `items` */
    
    CREATE TABLE `items` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(32) NOT NULL COMMENT '商品名称',
      `price` float(10,1) NOT NULL COMMENT '商品定价',
      `detail` text COMMENT '商品描述',
      `pic` varchar(64) DEFAULT NULL COMMENT '商品图片',
      `createtime` datetime NOT NULL COMMENT '生产日期',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
    
    /*Table structure for table `orderdetail` */
    
    CREATE TABLE `orderdetail` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `orders_id` int(11) NOT NULL COMMENT '订单id',
      `items_id` int(11) NOT NULL COMMENT '商品id',
      `items_num` int(11) DEFAULT NULL COMMENT '商品购买数量',
      PRIMARY KEY (`id`),
      KEY `FK_orderdetail_1` (`orders_id`),
      KEY `FK_orderdetail_2` (`items_id`),
      CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
      CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
    ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
    
    /*Table structure for table `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;
    
    /*Table structure for table `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;
    
    /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
    /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
    /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
    /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
    sql脚本

    1.3 jdbc程序

    使用jdbc查询mysql数据库中用户表的记录。

    创建java工程,加入jar包:

    数据库驱动包(mysql5.1

     

    上边的是mysql驱动。

    下边的是oracle的驱动。

     程序代码:

    package com.dzq.mybatis.jdbc;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    /**
     * 通过Jdbc程序,总结单独的jdbc程序,总结其中
     * 
     * @author 小强
     *
     */
    public class JdbcTest {
        public static void main(String[] args) {
            // 数据库连接
            Connection connection = null;
            // 预编译的Statement,可以提高数据库的性能
            PreparedStatement preparedStatement = null;
            // 结果集对象
            ResultSet resultSet = null;
    
            try {
                // 加载数据库驱动
                Class.forName("com.mysql.jdbc.Driver");
    
                // 通过驱动管理类获取数据库链接
                connection = DriverManager
                        .getConnection(
                                "jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8",
                                "root", "mysql");
                // 定义sql语句 ?表示占位符
                String sql = "select * from user where username = ?";
                // 获取预处理statement
                preparedStatement = connection.prepareStatement(sql);
                // 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
                preparedStatement.setString(1, "王五");
                // 向数据库发出sql执行查询,查询出结果集
                resultSet = preparedStatement.executeQuery();
                // 遍历查询结果集
                while (resultSet.next()) {
                    System.out.println(resultSet.getString("id") + "  "
                            + resultSet.getString("username"));
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 释放资源
                if (resultSet != null) {
                    try {
                        resultSet.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if (preparedStatement != null) {
                    try {
                        preparedStatement.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                if (connection != null) {
                    try {
                        connection.close();
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
    
            }
    
        }
    
    }
    JdbcTest

    1.4  问题总结

    1、数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响 数据库性能。

    设想:使用数据库连接池管理数据库连接。

    2、将sql语句硬编码到java代码中,如果sql 语句修改,需要重新编译java代码,不利于系统维护。

    设想:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。

    3、向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护。

    设想:将sql语句及占位符号和参数全部配置在xml中。

    4、从resultSet中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码,,不利于系统维护。

    设想:将查询的结果集,自动映射成java对象。

    2.mybatis框架

    2.1     mybatis是什么?

    mybatis是一个持久层的框架,是apache下的顶级项目。

    mybatis托管到goolecode下,再后来托管到github下(https://github.com/mybatis/mybatis-3/releases)。

    mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成(半自动化,大部分需要程序员编写sql)满足需要sql语句。

    mybatis可以将向 preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射

    2.2    mybatis框架

    3入门程序

    3.1 需求

    根据用户id(主键)查询用户信息

    根据用户名称模糊查询用户信息

    添加用户

    删除 用户

    更新用户

    3.2 环境

    java环境:jdk1.8.0_20

    eclipse:luna

    mysql:5.1

    jar包:mybatis-3.2.7.jar

    lib下:依赖包

    mybatis-3.2.7.jar:核心 包

    mybatis-3.2.7.pdf,操作指南

    加入mysql的驱动包

    3.3 log4j.properties

    # Global logging configuration
    #u5728u5f00u53d1u73afu5883u4e0bu65e5u5fd7u7ea7u522bu8981u8bbeu7f6eu6210DEBUGuff0cu751fu4ea7u73afu5883u8bbeu7f6eu6210infou6216error
    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

    3.4工程结构

    3.5 SqlMapConfig.xml

    配置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>
    
        
        <!-- 和spring整合后 environments配置将废除-->
        <environments default="development">
            <environment id="development">
            <!-- 使用jdbc事务管理,事务控制由mybatis-->
                <transactionManager type="JDBC" />
            <!-- 数据库连接池,由mybatis管理-->
                <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>
    
    </configuration>
    SqlMapConfig.xml

    3.6根据用户id(主键)查询用户信息

    3.6.1 创建po

    package com.dzq.mybatis.domain;
    
    import java.util.Date;
    
    public class User {
        // 属性名和数据库表的字段对应
        private int id;
        private String username;// 用户姓名
        private String sex;// 性别
        private Date birthday;// 生日
        private String address;// 地址
    
        public int getId() {
            return id;
        }
    
        public void setId(int 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;
        }
    
    }
    User.java

    3.6.2    映射文件

    映射文件命名:

    User.xml(原始ibatis命名),mapper代理开发映射文件名称叫XXXMapper.xml,比如:UserMapper.xml、ItemsMapper.xml

    在映射文件中配置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">
    <!--命名空间,对sql进行分类管理,实现sql隔离 注意:使用mapper代理的方法开发,namespace就有特殊重要的作用 -->
    <mapper namespace="test">
        <!-- 在映射文件中配置很多sql语句 -->
        <!-- 通过id查询用户表的记录 -->
        <!--通过select执行数据库的查询 
        id:标识映射文件中的sql,称为statemen的id 将sql语句封装到mappedstatement对象中
        #{}:表示占位符
        parameterType:指定输入参数类型,这里指定int型
        {id}:其中的id表示接收输入参数,如果输入参数是简单类型,#{}中参数名可以任意,可以是value或者其他名称
        resultType:指定sql输出结果所映射的java对象类型,select指定resultType将单条记录所映射成的java对象
         -->
        <select id="findUserById" parameterType="int" resultType="com.dzq.mybatis.domain.User">
         select * from user where id=#{id}
        </select>
    </mapper>
    User.xml

    3.6.3     在SqlMapConfig.xml加载映射文件

    在sqlMapConfig.xml中加载User.xml:

    <!-- 加载 映射文件 -->
        <mappers>
            <mapper resource="sqlmap/User.xml"/>
        </mappers>

    3.6.4     程序编写

    package com.dzq.mybatis.first;
    
    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 com.dzq.mybatis.domain.User;
    
    public class MybatisFirst {
        // 根据id查询用户的信息,得到一条记录结果
        public void findUserById(int id) throws IOException {
            //mybatis配置文件
            String resource="SqlMapConfig.xml";
            //得到配置文件流
            InputStream inputStream=Resources.getResourceAsStream(resource);
            //创建会话工厂,传入mybatis的配置文件的信息
            SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
            //通过工厂得到sqlsession
            SqlSession sqlSession=sqlSessionFactory.openSession();
            //通过sqlsession操作数据库
            //第一个参数:statement,映射文件中statement的id; 等于namespace+"."statement的id
            //第二个参数: parameter 指定和映射文件中parameter所匹配的parameterType的类型的 参数
            //sqlSession.selectOne结果是与映射文件中所匹配的resultType类型对象
            User user=sqlSession.selectOne("test.findUserById", 1);
            System.out.println(user);
            //释放资源
            sqlSession.close();
        }
    }
    MybatisFirst.java

    3.7  根据用户名称模糊查询用户信息

    3.7.1     映射文件

    使用User.xml,添加根据用户名称模糊查询用户信息的sql语句。

    <!-- 根据用户名称模糊查询用户信息  -->
        <!-- resultType:单条记录所映射的java对象类型
        ${}:拼接sql串,将接收到的参数不加任何修饰拼接到sql语句中
        使用${}拼接sql,会引起sql注入
        ${value}表示输入参数的内容,如果传入的类型是简单类型${}只能使用value
         -->
        <select id="findUserByUserName" parameterType="java.lang.String" resultType="com.dzq.mybatis.domain.User">
             select * from user where username like '%${value}%'
        </select>

    3.7.2   程序代码

    //根据用户名称模糊查询用户信息
        public void findUserByUserName() throws IOException{
            //mybatis配置文件
                    String resource="SqlMapConfig.xml";
                    //得到配置文件流
                    InputStream inputStream=Resources.getResourceAsStream(resource);
                    //创建会话工厂,传入mybatis的配置文件的信息
                    SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
                    //通过工厂得到sqlsession
                    SqlSession sqlSession=sqlSessionFactory.openSession();
                    //通过sqlsession操作数据库
                    //第一个参数:statement,映射文件中statement的id; 等于namespace+"."statement的id
                    //第二个参数: parameter 指定和映射文件中parameter所匹配的parameterType的类型的 参数
                    //sqlSession.selectList结果是与映射文件中所匹配的resultType类型对象
                    List<User> list=sqlSession.selectList("test.findUserByUserName", "小明");
                    System.out.println(list);
                    //释放资源
                    sqlSession.close();
        }

    3.8添加用户

    3.8.1映射文件

    在 User.xml中配置添加用户的Statement

    <!-- 添加用户 -->
        <!--  
        parameterType:输入参数类型是pojo(包括用户信息)
        #{}:指定pojo的属性名,接收到pojo的属性值,mybatis通过ognl获取属性值
        -->
        <insert id="addUser" parameterType="com.dzq.mybatis.domain.User">
            insert into user(id,username,birthday,sex,address) value(#{id},#{username},#{birthday},#{sex},#{address})
        </insert>

    3.8.2程序代码

    //添加用户信息
        @Test
        public void addUser() throws IOException {
            // mybatis配置文件
            String resource = "SqlMapConfig.xml";
            // 得到配置文件流
            InputStream inputStream = Resources.getResourceAsStream(resource);
            // 创建会话工厂,传入mybatis的配置文件的信息
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                    .build(inputStream);
            // 通过工厂得到sqlsession
            SqlSession sqlSession = sqlSessionFactory.openSession();
            //插入用户对象
            User user=new User();
            user.setUsername("贱贱");
            user.setSex("男");
            user.setAddress("山东临沂");
            user.setBirthday(new Date());
           sqlSession.insert("test.addUser", user);
           //提交事务
           sqlSession.commit();
            // 释放资源
            sqlSession.close();
        }

    3.8.3    自增主键返回

    mysql自增主键,执行insert提交之前自动生成一个自增主键。

    通过mysql函数获取到刚插入记录的自增主键:

    LAST_INSERT_ID()

    是insert之后调用此函数。

    修改insertUser定义:

    <insert id="addUser" parameterType="com.dzq.mybatis.domain.User">
            <!-- insert 插入数据返回到User对象中 
             select last_insert_id:得到刚插入进去数据的主键值,只适用于自增主键
             keyProperty:将要查询到的主键值设置到parameterType对象的那个属性
             order:相对于insert语句的执行顺序
            -->
            <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
                select last_insert_id()
            </selectKey>
            insert into user(username,birthday,sex,address) value(#{username},#{birthday},#{sex},#{address})
        </insert>

    3.8.14    非自增主键返回(使用uuid())

    使用mysql的uuid()函数生成主键,需要修改表中id字段类型为string,长度设置成35位。

    执行思路:

    先通过uuid()查询到主键,将主键输入 到sql语句中。

    执行uuid()语句顺序相对于insert语句之前执行。

    通过oracle的序列生成主键:

    <insert  id="insertUser" parameterType="cn.itcast.mybatis.po.User">
    <selectKey resultType="java.lang.Integer" order="BEFORE" 
    keyProperty="id">
    SELECT 自定义序列.NEXTVAL FROM DUAL
    </selectKey>
    insert into user(id,username,birthday,sex,address) 
             values(#{id},#{username},#{birthday},#{sex},#{address})
    </insert>

    注意这里使用的order是“BEFORE”

    3.9删除用户

    3.9.1映射文件

    <!-- 删除用户
        根据id删除用户,需要输入id值
         -->
        <delete id="deleteUser" parameterType="int" >
            delete from user where id=#{id}
        </delete>

    3.9.2程序代码

    //删除用户信息
            @Test
            public void deleteUser() throws IOException {
                // mybatis配置文件
                String resource = "SqlMapConfig.xml";
                // 得到配置文件流
                InputStream inputStream = Resources.getResourceAsStream(resource);
                // 创建会话工厂,传入mybatis的配置文件的信息
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                        .build(inputStream);
                // 通过工厂得到sqlsession
                SqlSession sqlSession = sqlSessionFactory.openSession();
                //传入id,根据id删除用户
               sqlSession.delete("test.deleteUser", 33);
               //提交事务
               sqlSession.commit();
                // 释放资源
                sqlSession.close();
            }

    3.10更新用户

    3.10.1映射文件

    <!-- 更新用户 
        分析:需要传入用户的id
        用户的更新信息
        parameterType,指定user对象,包括id和更新信息,注意,id必须存在
        #{id}接收user里的属性值
        -->
        <update id="updateUser" parameterType="com.dzq.mybatis.domain.User">
            update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
        </update>

    3.10.2程序代码

    // 更新用户信息
        @Test
        public void updateUser() throws IOException {
            // mybatis配置文件
            String resource = "SqlMapConfig.xml";
            // 得到配置文件流
            InputStream inputStream = Resources.getResourceAsStream(resource);
            // 创建会话工厂,传入mybatis的配置文件的信息
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                    .build(inputStream);
            // 通过工厂得到sqlsession
            SqlSession sqlSession = sqlSessionFactory.openSession();
            User user = new User();
            user.setId(32);
            user.setUsername("贱贱贱");
            user.setSex("女");
            user.setAddress("山东莱芜");
            user.setBirthday(new Date());
            // 传入user对象,根据id更新用户
            sqlSession.update("test.updateUser", user);
            // 提交事务
            sqlSession.commit();
            // 释放资源
            sqlSession.close();
        }

    3.11小结

     3.11.1      #{}和${}

    #{}表示一个占位符号,#{}接收输入参数,类型可以是简单类型,pojo、hashmap。

    如果接收简单类型,#{}中可以写成value或其它名称。

    #{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。

    ${}表示一个拼接符号,会引用sql注入,所以不建议使用${}。

    ${}接收输入参数,类型可以是简单类型,pojo、hashmap。

    如果接收简单类型,${}中只能写成value。

    ${}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。

    3.11.2     parameterType和resultType

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

    resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。

    3.11.3     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可以查询一条或多条记录。

    3.12   mybatis和hibernate本质区别和应用场景

    hibernate:是一个标准ORM框架(对象关系映射)。入门门槛较高的,不需要程序写sql,sql语句自动生成了。

    对sql语句进行优化、修改比较困难的。

    应用场景:

             适用与需求变化不多的中小型项目,比如:后台管理系统,erp、orm、oa。。

    mybatis:专注是sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。mybatis是一个不完全 的ORM框架,虽然程序员自己写sql,mybatis 也可以实现映射(输入映射、输出映射)。

    应用场景:

             适用与需求变化较多的项目,比如:互联网项目。

    企业进行技术选型,以低成本 高回报作为技术选型的原则,根据项目组的技术力量进行选择。

    4     mybatis开发dao的方法

    4.1     SqlSession使用范围

    4.1.1     SqlSessionFactoryBuilder

     通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory

    将SqlSessionFactoryBuilder当成一个工具类使用即可,不需要使用单例管理SqlSessionFactoryBuilder。

    在需要创建SqlSessionFactory时候,只需要new一次SqlSessionFactoryBuilder即可。

    4.1.2   SqlSessionFactory

    通过SqlSessionFactory创建SqlSession,使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例)。

    将来mybatis和spring整合后,使用单例模式管理sqlSessionFactory。

    4.1.3    SqlSession

    SqlSession是一个面向用户(程序员)的接口。

    SqlSession中提供了很多操作数据库的方法:如:selectOne(返回单个对象)、selectList(返回单个或多个对象)、。

    SqlSession是线程不安全的,在SqlSesion实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。

    SqlSession最佳应用场合在方法体内,定义成局部变量使用。

    4.2    原始dao开发方法(程序员需要写dao接口和dao实现类)

    4.2.1     思路

    程序员需要写dao接口和dao实现类。

    需要向dao实现类中注入SqlSessionFactory,在方法体内通过SqlSessionFactory创建SqlSession

    4.2.2     dao接口

    package com.dzq.mybatis.dao;
    
    import com.dzq.mybatis.domain.User;
    
    public interface UserDao {
        // 根据id查询用户信息
        public User findUserById(int id) throws Exception;
    
        // 添加用户
        public void addUser(User user) throws Exception;
    
        // 删除用户
        public void deleteUser(int id) throws Exception;
    
        // 修改用户信息
        public void updateUser(User user) throws Exception;
    }

    4.2.2     dao接口实现类

    package com.dzq.mybatis.dao.impl;
    
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    
    import com.dzq.mybatis.dao.UserDao;
    import com.dzq.mybatis.domain.User;
    
    public class UserDaoImpl implements UserDao {
        // 需要向dao实现类中注入SqlSessionFactory
        // 这里通过构造方法注入
        private SqlSessionFactory sqlSessionFactory;
    
        public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
            this.sqlSessionFactory = sqlSessionFactory;
        }
    
        @Override
        public User findUserById(int id) throws Exception {
            SqlSession sqlSession = sqlSessionFactory.openSession();
            User user = sqlSession.selectOne("test.findUserById", id);
            // 释放资源
            sqlSession.close();
            return user;
        }
    
        @Override
        public void addUser(User user) throws Exception {
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 执行插入
            sqlSession.insert("test.addUser", user);
            // 提交事务
            sqlSession.commit();
            // 释放资源
            sqlSession.close();
        }
    
        @Override
        public void deleteUser(int id) throws Exception {
            SqlSession sqlSession = sqlSessionFactory.openSession();
            sqlSession.delete("test.deleteUser", id);
            // 提交事务
            sqlSession.commit();
            // 释放资源
            sqlSession.close();
    
        }
    
        @Override
        public void updateUser(User user) throws Exception {
            SqlSession sqlSession = sqlSessionFactory.openSession();
            sqlSession.update("test.updateUser", user);
            // 提交事务
            sqlSession.commit();
            // 释放资源
            sqlSession.close();
        }
    
    }

    4.2.4  测试代码:

    package com.dzq.mybatis.test;
    
    import java.io.InputStream;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.Before;
    import org.junit.Test;
    
    import com.dzq.mybatis.dao.UserDao;
    import com.dzq.mybatis.dao.impl.UserDaoImpl;
    import com.dzq.mybatis.domain.User;
    
    public class UserDaoImplTest {
    
        private SqlSessionFactory sqlSessionFactory;
    
        @Before
        public void setUp() throws Exception {
            // 创建sqlSessionFactory
            // mybatis配置文件
            String resource = "SqlMapConfig.xml";
            // 得到配置文件流
            InputStream inputStream = Resources.getResourceAsStream(resource);
            // 创建会话工厂,传入mybatis的配置文件的信息
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }
    
        @Test
        public void testFindUserById() throws Exception {
            // 创建UserDao对象
            UserDao userdao = new UserDaoImpl(sqlSessionFactory);
            // 调用userDao方法
            User user=userdao.findUserById(1);
            System.out.println(user.getUsername());
        }
    
    }

    4.2.5     总结原始 dao开发问题

    1、dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。

    2、调用sqlsession方法时将statement的id硬编码了

    3、调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。

    4.3    mapper代理方法(程序员只需要mapper接口(相当 于dao接口))

    4.3.1     思路(mapper代理开发规范)

    程序员还需要编写mapper.xml映射文件

    程序员编写mapper接口需要遵循一些开发规范,mybatis可以自动生成mapper接口实现类代理对象。

    开发规范:

    1、在mapper.xml中namespace等于mapper接口地址

    <!--命名空间,对sql进行分类管理,实现sql隔离 注意:使用mapper代理的方法开发,namespace就有特殊重要的作用 
    namespace等于mapper接口地址
    -->
    <mapper namespace="com.dzq.mybatis.mapper.UserMapper">

    2、mapper.java接口中的方法名和mapper.xml中statement的id一致

    3、mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致。

    4、mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致。

    <select id="findUserById" parameterType="int" resultType="com.dzq.mybatis.domain.User">
         select * from user where id=#{id}
        </select>
    // 根据id查询用户信息
        public User findUserById(int id) throws Exception;

    总结:

    以上开发规范主要是对下边的代码进行统一生成:

    User user = sqlSession.selectOne("test.findUserById", id);

    sqlSession.insert("test.insertUser", user);

    。。。。

    4.3.2     mapper.java

    package com.dzq.mybatis.mapper;
    
    import java.util.List;
    
    import com.dzq.mybatis.domain.User;
    
    public interface UserMapper {
        
        public User findUserById(int id) throws Exception;
    }

    4.3.3 mapper.xml

    <select id="findUserById" parameterType="int" resultType="com.dzq.mybatis.domain.User">
         select * from user where id=#{id}
        </select>
        

    4.3.4     在SqlMapConfig.xml中加载mapper.xml

    <!-- 加载 映射文件 -->
        <mappers>
            <mapper resource="sqlmap/User.xml"/>
            <mapper resource="mapper/UserMapper.xml"/>
        </mappers>

    4.3.5    测试

    package com.dzq.mybatis.test;
    
    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.Before;
    import org.junit.Test;
    
    import com.dzq.mybatis.domain.User;
    import com.dzq.mybatis.mapper.UserMapper;
    
    public class UserMapperTest {
        private SqlSessionFactory sqlSessionFactory;
        @Before
        public void setUp() throws Exception {
            // 创建sqlSessionFactory
                    // mybatis配置文件
                    String resource = "SqlMapConfig.xml";
                    // 得到配置文件流
                    InputStream inputStream = Resources.getResourceAsStream(resource);
                    // 创建会话工厂,传入mybatis的配置文件的信息
                    sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }
    
        @Test
        public void testFindUserById() throws Exception {
            
            SqlSession sqlSession=sqlSessionFactory.openSession();
            //创建一个usermapper的对象
            UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
            //调用userMapper方法
            User user=userMapper.findUserById(1);
            System.out.println(user.getUsername());
            
        }
    
    }

    4.3.6    整个接口

    package com.dzq.mybatis.mapper;
    
    import java.util.List;
    
    import com.dzq.mybatis.domain.User;
    
    public interface UserMapper {
    
        // 根据id查询用户信息
        public User findUserById(int id) throws Exception;
    
        // 添加用户
        public void addUser(User user) throws Exception;
    
        // 删除用户
        public void deleteUser(int id) throws Exception;
    
        // 根据用户名称查询用户列表
        public List<User> findUserByUserName(String username) throws Exception;
    }

    4.3.7     一些问题总结

    4.3.7.1              代理对象内部调用selectOne或selectList

    如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库。

    如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库。

    4.3.7.2              mapper接口方法参数只能有一个是否影响系统 开发

    mapper接口方法参数只能有一个,系统是否不利于扩展维护。

    系统 框架中,dao层的代码是被业务层公用的。

    即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求。

    注意:持久层方法的参数可以包装类型、map。。。,service方法中建议不要使用包装类型(不利于业务层的可扩展)。

    5     SqlMapConfig.xml

    mybatis的全局配置文件SqlMapConfig.xml,配置内容如下:

    properties(属性)

    settings(全局配置参数)

    typeAliases(类型别名)

    typeHandlers(类型处理器)

    objectFactory(对象工厂)

    plugins(插件)

    environments(环境集合属性对象)

    environment(环境子属性对象)

    transactionManager(事务管理)

    dataSource(数据源)

    mappers(映射器)

    5.1     properties属性

    需求:

    将数据库连接参数单独配置在db.properties中,只需要在SqlMapConfig.xml中加载db.properties的属性值。

    在SqlMapConfig.xml中就不需要对数据库连接参数硬编码。

    将数据库连接参数只配置在db.properties中,原因:方便对参数进行统一管理,其它xml可以引用该db.properties。

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/mybatis
    jdbc.username=root
    jdbc.password=
    <!-- 加载属性文件 -->
        <properties resource="db.properties">
            <!--properties中还可以配置一些属性名和属性值 -->
            <!-- <property name="jdbc.driver" value=""/> -->
        </properties>

    properties特性:

    注意: MyBatis 将按照下面的顺序来加载属性:

          在 properties 元素体内定义的属性首先被读取。

          然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。

          最后读取parameterType传递的属性,它会覆盖已读取的同名属性。

    建议:

    不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中。

    在properties文件中定义属性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX

    5.2   settings全局参数配置

    mybatis框架在运行时可以调整一些运行参数。

    比如:开启二级缓存、开启延迟加载。。

    全局参数将会影响mybatis的运行行为。

     

    5.3     typeAliases(别名)重点

    5.3.1     需求

    在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。

    如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。

    5.3.2   mybatis默认支持别名

    5.3.3     自定义别名

    5.3.3.1              单个别名定义

    <!-- 别名定义 -->
        <typeAliases>
            <!-- 针对单个别名的定义
            type:类型路径
            alias:别名
             -->
            <typeAlias type="com.dzq.mybatis.domain.User" alias="user"/>
        </typeAliases>

    引用别名:

    <select id="findUserById" parameterType="int" resultType="user">
         select * from user where id=#{id}
        </select>

    5.3.3.2  批量定义别名(常用)

    <!-- 批量别名定义
            指定包名,mybatis自动扫描domain类,自动定义别名,别名就是类名
             -->
             <package name="com.dzq.mybatis.domain"/>

    5.4    typeHandlers(类型处理器)

    mybatis中通过typeHandlers完成jdbc类型和java类型的转换。

    通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义.

    mybatis支持类型处理器:

    5.5  mappers(映射配置)

    5.5.1     通过resource加载单个映射文件

    <!-- 加载 映射文件 -->
        <mappers>
            <mapper resource="sqlmap/User.xml" />
            <mapper resource="mapper/UserMapper.xml" />
        </mappers>

    5.5.2   通过mapper接口加载单个mapper

    <!--通过mapper接口加载单个mapper 
            遵循一些规范:需要将mapper接口的类名和mapper.xml映射文件名称保持一致,且在一个目录
            上边规范的前提是:你使用的是mapper代理的方法
            -->
            <mapper class="com.dzq.mybatis.mapper.UserMapper"/>

    需要将mapper接口的类名和mapper.xml映射文件名称保持一致,且在一个目录

    5.5.3  批量加载mapper(推荐使用)

    <!--批量加载mapper(推荐使用) 
            指定mapper接口的包名,mybatis自动扫描包下所有mapper接口进行加载
            遵循一些规范:需要将mapper接口的类名和mapper.xml映射文件名称保持一致,且在一个目录
            上边规范的前提是:你使用的是mapper代理的方法
             -->
            <package name="com.dzq.mybatis.mapper"/>

    6    输入映射

    通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型。

    6.1     传递pojo的包装对象

    6.1.1     需求

    完成用户信息的综合查询,需要传入查询条件很复杂(可能包括用户信息、其它信息,比如商品、订单的)

    6.1.2     定义包装类型pojo

    针对上边需求,建议使用自定义的包装类型的pojo。

    在包装类型的pojo中将复杂的查询条件包装进去。

    package com.dzq.mybatis.domain;
    
    public class UserQueryVo {
    //这里包装所需要的查询条件
        //用户查询条件
        private UserCustom userCustom;
        //还可以包装其他的查询条件 商品、订单
    
        public UserCustom getUserCustom() {
            return userCustom;
        }
    
        public void setUserCustom(UserCustom userCustom) {
            this.userCustom = userCustom;
        }
        
    }

    6.1.3    mapper.xml

    在UserMapper.xml中定义用户信息综合查询(查询条件复杂,通过高级查询进行复杂关联查询)。

     <!-- 用户信息的综合查询
        #{userCustom.sex}:取出包装类型的性别信息
        ${userCustom.username}:取出包装类中的用户名
         -->
        <select id="findUserList" parameterType="com.dzq.mybatis.domain.UserQueryVo" resultType="com.dzq.mybatis.domain.UserCustom">
            select * from user where user.sex=#{userCustom.sex} and user.username like '%${userCustom.username}%'
        </select>

    6.1.4     mapper.java

    //用户信息综合查询
        public List<UserCustom> findUserList(UserQueryVo userQueryVo) throws Exception;

    6.1.5    测试代码

     @Test
        public void testFindUserList() throws Exception {
    
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 创建一个usermapper的对象
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            //创建包装对象,设置查询条件
            UserQueryVo userQueryVo=new UserQueryVo();
            UserCustom userCustom=new UserCustom();
            userCustom.setSex("1");
            userCustom.setUsername("小明");
            userQueryVo.setUserCustom(userCustom);
            // 调用userMapper方法
            
            List<UserCustom> list = userMapper.findUserList(userQueryVo);
            //sqlSession.close();
            System.out.println(list);
    
        }

    7     输出映射

    7.1     resultType

    使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。

    如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。

    只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象,不一致的属性的值为null。

    7.1.1     输出简单类型

    7.1.1.1              需求

    用户信息的综合查询列表总数,通过查询总数和上边用户综合查询列表才可以实现分页。

    7.1.1.2              mapper.xml

    <!-- 用户信息综合查询总数
        parameterType:输入类型和findUserList一致
        resultType:输出结果类型为整型
         -->
        <select id="findUserCount"  parameterType="com.dzq.mybatis.domain.UserQueryVo" resultType="int">
              select count(*) from user where user.sex=#{userCustom.sex} and user.username like '%${userCustom.username}%'
        </select>

    7.1.1.3              mapper.java

    //用户信息综合查询总数
       public int findUserCount(UserQueryVo userQueryVo) throws Exception;

    7.1.1.4             测试代码

     @Test
        public void testFindUserCount() throws Exception {
    
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 创建一个usermapper的对象
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            //创建包装对象,设置查询条件
            UserQueryVo userQueryVo=new UserQueryVo();
            UserCustom userCustom=new UserCustom();
            userCustom.setSex("1");
            userCustom.setUsername("小明");
            userQueryVo.setUserCustom(userCustom);
            // 调用userMapper方法
            
            int count = userMapper.findUserCount(userQueryVo);
            System.out.println(count);
    
        }

    7.1.1.5             小结

    查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射。

    7.1.2   输出pojo对象和pojo列表

    不管是输出的pojo单个对象还是一个列表(list中包括pojo),在mapper.xml中resultType指定的类型是一样的。

    在mapper.java指定的方法返回值类型不一样:

             1、输出单个pojo对象,方法返回值是单个对象类型

              

        // 根据id查询用户信息
        public User findUserById(int id) throws Exception;

             2、输出pojo对象list,方法返回值是List<Pojo>

             

        // 根据用户名称查询用户列表
        public List<User> findUserByUserName(String username) throws Exception;

    生成的动态代理对象中是根据mapper方法的返回值类型确定是调用selectOne(返回单个对象调用)还是selectList (返回集合对象调用 ).

    7.2     resultMap

    mybatis中使用resultMap完成高级输出结果映射。(一对一、一对多、多对多)(小入门)

    7.2.1     resultMap使用方法

    如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。

    1、定义resultMap

    2、使用resultMap作为statement的输出映射类型

    7.2.2     将下边的sql使用User完成映射

    SELECT id id_,username username_ FROM USER WHERE id=#{value}

    User类中属性名和上边查询列名不一致。

    7.2.2.1              定义reusltMap

     <!-- 定义resultMap
        将 select id id_,username username_ from user where id=#{id}查询和User做一个映射
        type:resultMap最终映射的java对象类型,可以使用别名
        id:对resultMap的唯一标识
         -->
        <resultMap type="user" id="userResultMap">
            <!-- id表示查询结果集中唯一的标识 
            column:查询出来的列名
            property:type中指定的pojo中的属性名
            最终resultMap对column和property做一个映射关系(对应关系)
            -->
            <id column="id_" property="id"/>
            <!-- 对普通列的定义
            column:查询出来的列名
            property:type中指定的pojo中的属性名
            最终resultMap对column和property做一个映射关系(对应关系)
             -->
            <result column="username_" property="username"/>
            
        </resultMap>

    7.2.2.2       使用resultMap作为statement的输出映射类型

     <!-- 使用resultMap来进行输出的映射 
        resultMap:指定定义的resultMap的id,如果resultMap在其他映射文件中,前边需要加上namespace
        
        -->
        <select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
         select id id_,username username_ from user where id=#{id}
        </select>

    7.2.2.3            mapper.java

    //根据id查询用户信息,使用resultMap输出
       public User findUserByIdResultMap(int id)throws Exception;

    7.2.2.4            测试

    @Test
        public void testFindUserByIdResultMap() throws Exception {
    
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 创建一个usermapper的对象
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 调用userMapper方法
            User user = userMapper.findUserByIdResultMap(1);
            System.out.println(user.getUsername());
    
        }

    7.3    小结

    使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。

    如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。

    8      动态sql

    8.1     什么是动态sql

    mybatis核心 对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。

    8.2     需求

    用户信息综合查询列表和用户信息查询列表总数这两个statement的定义使用动态sql。

    对查询条件进行判断,如果输入参数不为空才进行查询条件拼接。

    8.3     mapper.xml

     <!-- 用户信息的综合查询
        #{userCustom.sex}:取出包装类型的性别信息
        ${userCustom.username}:取出包装类中的用户名
         -->
        <select id="findUserList" parameterType="com.dzq.mybatis.domain.UserQueryVo" resultType="com.dzq.mybatis.domain.UserCustom">
            select * from user 
            <!-- where 可以自动的去掉条件中的第一个and -->
            <where>
                <if test="userCustom!=null">
                <if test="userCustom.sex!=null and userCustom.sex!=''">
                  and user.sex=#{userCustom.sex} 
                </if>
                <if test="userCustom.username!=null and userCustom.username!=''">
                  and user.username like '%${userCustom.username}%'
                </if>
            </if>
            </where>
            
            
        </select>
        
        <!-- 用户信息综合查询总数
        parameterType:输入类型和findUserList一致
        resultType:输出结果类型为整型
         -->
        <select id="findUserCount"  parameterType="com.dzq.mybatis.domain.UserQueryVo" resultType="int">
              select count(*) from user 
               <!-- where 可以自动的去掉条件中的第一个and -->
            <where>
                <if test="userCustom!=null">
                <if test="userCustom.sex!=null and userCustom.sex!=''">
                  and user.sex=#{userCustom.sex} 
                </if>
                <if test="userCustom.username!=null and userCustom.username!=''">
                  and user.username like '%${userCustom.username}%'
                </if>
            </if>
            </where>
        </select>

    8.4   测试代码

     public void testFindUserList() throws Exception {
    
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 创建一个usermapper的对象
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            //创建包装对象,设置查询条件
            UserQueryVo userQueryVo=new UserQueryVo();
            UserCustom userCustom=new UserCustom();
            
            //由于使用了动态sql,如果不设置某个值,这个条件不会拼接到sql中
            //userCustom.setSex("1");
            userCustom.setUsername("小明");
            userQueryVo.setUserCustom(userCustom);
            // 调用userMapper方法
            
            List<UserCustom> list = userMapper.findUserList(userQueryVo);
            //sqlSession.close();
            System.out.println(list);
    
        }

    8.5    sql片段

    8.5.1     需求

    将上边实现的动态sql判断代码块抽取出来,组成一个sql片段。其它的statement中就可以引用sql片段。

    方便程序员进行开发。

    8.5.2     定义sql片段

    !--定义sql片段
        id:sql片段的唯一标识
               经验:基于单表定义sql片段,这样可重用性才高
               sql片段中不要包括where
          -->
          <sql id="query_user_where">
                <if test="userCustom!=null">
                <if test="userCustom.sex!=null and userCustom.sex!=''">
                  and user.sex=#{userCustom.sex} 
                </if>
                <if test="userCustom.username!=null and userCustom.username!=''">
                  and user.username like '%${userCustom.username}%'
                </if>
            </if>
          </sql>

    8.5.3    引用sql片段

    在mapper.xml中定义的statement中引用sql片段:

     <!-- 用户信息的综合查询
        #{userCustom.sex}:取出包装类型的性别信息
        ${userCustom.username}:取出包装类中的用户名
         -->
        <select id="findUserList" parameterType="com.dzq.mybatis.domain.UserQueryVo" resultType="com.dzq.mybatis.domain.UserCustom">
            select * from user 
            <!-- where 可以自动的去掉条件中的第一个and -->
            <where>
                <!--  这就是引用sql片段的id 如果refid不在本mapper中,需要加上namespace-->
              <include refid="query_user_where"> </include>
              <!-- 在这里还会引用其他sql片段,商品等 -->
            </where>
            
            
        </select>
      <!-- 用户信息综合查询总数
        parameterType:输入类型和findUserList一致
        resultType:输出结果类型为整型
         -->
        <select id="findUserCount"  parameterType="com.dzq.mybatis.domain.UserQueryVo" resultType="int">
              select count(*) from user 
               <!-- where 可以自动的去掉条件中的第一个and -->
            <where>
                  <!--  这就是引用sql片段的id 如果refid不在本mapper中,需要加上namespace-->
              <include refid="query_user_where"> </include>
              <!-- 在这里还会引用其他sql片段,商品等 -->
            </where>
        </select>

    8.6    foreach

    向sql传递数组或List,mybatis使用foreach解析

    8.6.1     需求

    在用户查询列表和查询总数的statement中增加多个id输入查询。

    sql语句如下:

    两种方法:

    SELECT * FROM USER WHERE id=1 OR id=10 OR id=16

    SELECT * FROM USER WHERE id IN(1,10,16)

    8.6.2    在输入参数类型中添加List<Integer> ids传入多个id

        //传入多个id
            private List<Integer> ids;
    
        public List<Integer> getIds() {
            return ids;
        }
    
        public void setIds(List<Integer> ids) {
            this.ids = ids;
        }

    8.6.3     修改mapper.xml

    WHERE id=1 OR id=10 OR id=16

    在查询条件中,查询条件定义成一个sql片段,需要修改sql片段。

     <if test="ids!=null">
                    <!-- 使用foreach遍历我们传入的ids 
                    collection:指定输入对象中集合属性
                    item:每次遍历生成对象名
                    open:开始遍历时要拼接的串
                    close:结束遍历时拼接的串
                    separator:遍历的两个对象中间所要拼接的串
                    -->
                    <!-- 使用实现下边的sql拼接
                    and (id=1 or id=10 or id=16)
                     -->
                    <foreach collection="ids" item="user_id" open="and (" close=")" separator="or">
                        <!--  每次遍历所需要拼接的串-->
                        id=#{user_id}
                    </foreach>
                </if>

    8.6.4     测试代码

     @Test
        public void testFindUserList() throws Exception {
    
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 创建一个usermapper的对象
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            //创建包装对象,设置查询条件
            UserQueryVo userQueryVo=new UserQueryVo();
            UserCustom userCustom=new UserCustom();
            
            //由于使用了动态sql,如果不设置某个值,这个条件不会拼接到sql中
            userCustom.setSex("1");
            userCustom.setUsername("小明");
            //传入多个id
            List <Integer> ids=new ArrayList<Integer>();
            ids.add(1);
            ids.add(10);
            ids.add(16);
            userQueryVo.setUserCustom(userCustom);
            //将ids传入statement中
            userQueryVo.setIds(ids);
            
            // 调用userMapper方法
            
            List<UserCustom> list = userMapper.findUserList(userQueryVo);
            //sqlSession.close();
            System.out.println(list.get(0).getUsername());
    
        }

    8.6.5  另外一个sql的实现:

    <!--实现  and id in(1,10,16)拼接  -->
                      <foreach collection="ids" item="user_id" open="  and id in(" close=")" separator=",">
                        <!--  每次遍历所需要拼接的串-->
                        #{user_id}
                    </foreach>
  • 相关阅读:
    时间复杂度和空间复杂度的故事
    Go -- 并发编程的两种限速方法
    Go -- type 和断言 interface{}转换
    Go -- 实现二叉搜索树
    Go语言程序的状态监控
    Go -- 中开启gctrace
    Go --- GC优化经验
    Mysql 性能优化20个原则(4)
    Mysql 性能优化20个原则(3)
    查看 activex 组件的方法
  • 原文地址:https://www.cnblogs.com/xiaoduc-org/p/5517727.html
Copyright © 2011-2022 走看看