MyBatis(半自动 轻量级 持久层框架)

概述

sql与java编码分离 ;sql是开发人员控制

只需要掌握sql即可

mybatis以简化JDBC操作 实现数据的持久层

  1. ORM:Object Relational Maping
  2. person对象-->ponson数据库表
  3. ORM:概念,MybatisORM的一个实现/Hibernate

课时1 Mybatis配置以及入门示例

1.)导入所需的jar包 mvn

  1. <dependency>
  2. <groupId>org.mybatis</groupId>
  3. <artifactId>mybatis</artifactId>
  4. <version>3.4.5</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>mysql</groupId>
  8. <artifactId>mysql-connector-java</artifactId>
  9. <version>5.1.6</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>log4j</groupId>
  13. <artifactId>log4j</artifactId>
  14. <version>1.2.17</version>
  15. </dependency>

.2)Mapper 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">
<mapper namespace="org.hbz.dao.IPersonDao">

.3)mapper SQL映射配置——编写实体对应数据库

<mapper namespace="org.hbz.dao.IPersonDao">
        <select id="selectPersonById" parameterType="Integer" resultType="org.hbz.entity.Person">
            select * from person where id=#{id}
        </select>
</mapper>
package org.hbz.entity;

public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private String sex;

    public Person() {

    }

    public Person(Integer id, String name, Integer age, String sex) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}

.4) 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">

.5)mybatis的主配置文件体

<configuration>
    <environments default="mysql">
        <environment id="mysql">
<!--                配置事务-->
            <transactionManager type="JDBC">
            </transactionManager>
<!--            配置数据库连接信息-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
<!--加载sql映射文件-->
    <mappers>
<!--        注意如果是xml文件 格式是../../..-->
        <mapper resource="org/hbz/dao/personMapper.xml"></mapper>
    </mappers>
</configuration>

.6)log4j配置文件如下

### 设置###
log4j.rootLogger = debug,stdout,D,E

### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log 
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

.7)dao层

/**
     * 按照id查询一个学生
     * @param id
     * @return
     */
    Student selectStudentById(Integer id);

.8)测试类

package org.hbz.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 org.hbz.dao.IPersonDao;
import org.hbz.entity.Person;

import java.io.IOException;
import java.io.Reader;

/**
 * 测试类
 */
public class MybatisTest {
    public static void main(String [] args) throws IOException {
        //加载mybatis配置文件(为了访问数据库)
       Reader reader= Resources.getResourceAsReader("config.xml");
       //创建工厂
        SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
        //打开一次会话
        SqlSession session=sessionFactory.openSession();
        //获取代理对象
        IPersonDao iPersonDao = (IPersonDao)session.getMapper(IPersonDao.class);
        //执行方法
        Person person = iPersonDao.selectPersonById(1);
        System.out.println(person.getName());

        //关闭流
        reader.close();
        //关闭会话
        session.close();
    }

}

.8)mybatis通过namespace加id定位出唯一的sql

课时2 Mybatis 动态代理方式实现增删改查(mybatis接口方式开发)以及配置分析

官方推荐

另外一种就是statement开发

原则:约定优于配置

.1)分析主配置文件

<configuration>
    <environments default="mysql">
        <environment id="mysql">
<!--                配置事务-->
            <transactionManager type="JDBC">
            </transactionManager>
<!--            配置数据库连接信息-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
<!--加载sql映射文件-->
    <mappers>
<!--        注意如果是xml文件 格式是../../..-->
        <mapper resource="org/hbz/dao/personMapper.xml"></mapper>
    </mappers>
</configuration>

分析如下:

1.environments标签和environment关系

default:代表在哪个环境上运行项目

id:代表的是环境标识 每一个id都代表一个环境

上诉的总结:通过default 指定的id值产生映射关系 可以随意的更换运行的环境 列如第一个环境是本机的数据库 第二个是真正的发布项目的数据库

也可以通过java代码来指定运行的环境

第二值就是更改默认运行的环境

SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader,"mysql");

2.dataSource标签

数据源类型:

            POOLED:使用数据库连接池

            UNPOOLED:传统的JDBC模式(每次访问数据库 均需要打开 关闭等数据库操作 但是打开关闭数据库是比较消耗性能的)

            JNDI:从tomcat中获取一个内置的数据库连接池 (数据连接池--数据源)

3.transactionManager标签

提交事务方式:

            JDBC:利用JDBC方式处理事务 (commit rollback close)

            MANAGED:将事务交由 其他组件去托管  (spring,jobss),默认 会关闭连接  如果不想关闭使用下面代码
<property name="closeCConnection" value="false"/>配置在事务标签下

.2)分析sql映射文件

<mapper namespace="org.hbz.dao.IStudentDao">
    <select id="selectStudentById" resultType="org.hbz.entity.Student" parameterType="Integer">
        select * from student where stuno=#{stuno}
    </select>

    <select id="selectAllStudent" resultType="org.hbz.entity.Student">
        select * from student
    </select>

    <insert id="addStudent" parameterType="org.hbz.entity.Student">
        insert into student(stuName,stuAge,graName) values(#{stuName},#{stuAge},#{graName})
    </insert>

    <delete id="deleteStudent" parameterType="Integer">
        delete from student where id=#(id)
    </delete>

    <update id="updateStudent" parameterType="org.hbz.entity.Student">
        update into student set stuName=#{stuName},stuAge=#{stuAge},graName=#{graName} where id=#{id}

</mapper>

1.mybatis约定:resultType和parameter只能有一个值

2.select :标签代表查询操作

3.namespace:映射的接口路径

4.id:代表接口中的方法名称

5.parameterType:

        5.1 代表接口中的方法参数类型

        5.2 如果parameterType的参数是8个基本类型(基本类型+String)  占位符里面的值可以随便填写#{xxx}

        5.3 如果是对象类型 必须写的是对象的属性名称 #{属性名}

6.resultMap:

        6.1 代表接口方法的返回值

        6.2 如果返回值是一个 对象(如Student) ,则无论是返回一个还是多个,再resultType都写成org.hbz.entity.Student

.7)dao层

public interface IStudentDao {
    /**
     * 按照id查询一个学生
     * @param id
     * @return
     */
    Student selectStudentById(Integer id);

    /**
     * 查询全部学生
     * @return
     */
    List<Student> selectAllStudent();

    /**
     * 增加一个学生
     * @param student
     * @return
     */
    Integer addStudent(Student student);

    /**
     * 根据id删除学生
     * @param id
     * @return
     */
    Integer deleteStudent(Integer id);

    /**
     * 按照id更新学生
     * @param student
     * @return
     */
    Integer updateStudent(Student student);
}

1.如果调用了dao层的方法 则会通过接口名称来查找配置的文件namespace

并且通过方法名值映射id得到sql语句

2.习惯:既然dao层和mapper.xml方法一起 而在idea中resources的包和java源码的包结构一样即可 会自动放在一起

.8)测试类

  //查询一个学生
    public static void selectOneStudent() throws IOException {
        Reader reader = Resources.getResourceAsReader("config.xml");
        SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession session=sessionFactory.openSession();
        IStudentDao iStudentDao=session.getMapper(IStudentDao.class);
        Student student = iStudentDao.selectStudentById(1);
        System.out.println(student);
        session.close();
        reader.close();
    }
    //查询全部学生
    public static void selectAll() throws IOException {
        Reader reader = Resources.getResourceAsReader("config.xml");
        SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession session=sessionFactory.openSession();
        IStudentDao iStudentDao=session.getMapper(IStudentDao.class);
        List<Student> stus = iStudentDao.selectAllStudent();
        System.out.println(stus);
        session.close();
        reader.close();
    }

    //增加一个学生
    public static void addStu() throws IOException {
        Reader reader = Resources.getResourceAsReader("config.xml");
        SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession session=sessionFactory.openSession();
        IStudentDao iStudentDao=session.getMapper(IStudentDao.class);
        Student stu=new Student();

        stu.setStuName("王五");
        stu.setStuAge(20);
        stu.setGraName("S1");

        Integer count = iStudentDao.addStudent(stu);
        session.commit();
        System.out.println(count);
        session.close();
        reader.close();
    }

    //删除一个学生
    public static void deleteStu() throws IOException {
        Reader reader = Resources.getResourceAsReader("config.xml");
        SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession session=sessionFactory.openSession();
        IStudentDao iStudentDao=session.getMapper(IStudentDao.class);

        Integer count = iStudentDao.deleteStudent(2);
        session.commit();
        System.out.println(count);
        session.close();
        reader.close();
    }

    //更新学生
    public static void updateStudent() throws IOException {
        Reader reader = Resources.getResourceAsReader("config.xml");
        SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession session=sessionFactory.openSession();
        IStudentDao iStudentDao=session.getMapper(IStudentDao.class);
        Student stu=new Student();
        stu.setStuNo(3);
        stu.setStuName("王子");
        stu.setStuAge(20);
        stu.setGraName("S2");

        Integer count = iStudentDao.updateStudent(stu);
        session.commit();
        System.out.println(count);
        session.close();
        reader.close();
    }

1.通过getMapper(接口.class)方法反射出类来得到这个接口

之后调用接口中的方法即可

课时3:属性文件丶全局参数丶别名丶类型转换器丶resultMap

.1)如何配置连接数据库的参数(主配置文件中)

1.首先创建一个properties的文件 把连接的参数写入
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/ssm
username=root
password=root
2.在主配置文件中引入该配置文件
<!--    引入-->
    <properties resource="mysql.properties"></properties>
3.通过跟el表达式的形式填入value值

                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>

.2)如何设置全局参数

1.下面有一张全局参数的键和值

2.在主配置文件中配置

 <settings>
        <setting name="cacheEnabled" value="false"/>
    </settings>
        name代表要执行查找键   value 代表键的值

.3)如何配置别名

1.配置单个别名 (在主配置文件中)
<typeAliases>
        <typeAlias type="org.hbz.entity.Student" alias="student"></typeAlias>
    </typeAliases>
如果设置了别名  只要要用到这个全限定类名了  都可以使用别名  并且不区分大小写

        type:代表全限定类名                            alias:代表别名

2.配置多个别名(在主配置中)

    <typeAliases> 
<package name="org.hbz.entity"/>
    </typeAliases>
如果设置了别名  只要要用到这个全限定类名了  都可以使用别名  并且不区分大小写

            name:代表全限定包名   而别名就是类本身

3.除了自定义别名mybatis内置的一些别名如下

.4)类型处理器(类型转换器)

1.mybatis自带的一些类型处理器

2.自定义mybatis类型处理器

                java-数据库(jdbc类型)

实例:

实体类Student boolean stuSex true:男 false :女

数据库 student int stuSex 1:男 0::女

自定义类型转换器(boolean-int) 步骤:

(1) 创建转换器

            需要实现TypeHandler接口

            通过阅读源码发现BaseTypeHandler是实现类  因此实现类型转换器有两种选择

            i:实现TypeHandler

            ii:继承BaseTypeHandler
package org.hbz.converter;


import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class BooleanAndInt extends BaseTypeHandler<Boolean> {

    //set:java-->数据库

    /**
     *
     * @param preparedStatement PreparedStatement对象
     * @param i PreparedStatement对象操作参数的位置
     * @param o java值
     * @param jdbcType jdbc操作数据库的值
     * @throws SQLException
     */
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Boolean o, JdbcType jdbcType) throws SQLException {
                if (o){//true编程1
                    preparedStatement.setInt(i,1);
                }else{//false就是0
                    preparedStatement.setInt(i,0);
                }
    }
    //get:数据库-->java

    /**
     *
     * @param resultSet 数据集
     * @param s 数据库列名
     * @return 返回转换后的值
     * @throws SQLException
     */
    @Override
    public Boolean getNullableResult(ResultSet resultSet, String s) throws SQLException {
        int bool=resultSet.getInt(s);
        return (bool==1?true:false);
    }
    //get:数据库-->java

    /**
     *
     * @param resultSet 数据集
     * @param i 下标
     * @return 转换后的数据
     * @throws SQLException
     */
    @Override
    public Boolean getNullableResult(ResultSet resultSet, int i) throws SQLException {
        int bool=resultSet.getInt(i);
        return (bool==1?true:false);
    }
    //get:数据库-->java

    /**
     *
     * @param callableStatement 存储过程对象
     * @param i 下标
     * @return 转换后的值
     * @throws SQLException
     */
    @Override
    public Boolean getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        int bool=callableStatement.getInt(i);
        return (bool==1?true:false);
    }
}
(2)配置转换器(主配置文件中)
 <typeHandlers>
 <typeHandler handler="org.hbz.converter.BooleanAndInt" javaType="boolean" jdbcType="Integer"></typeHandler>
    </typeHandlers>
handler:代表映射转换类型的类            javaType:java的类型    jdbcType:数据库的类型

(3)配置sql映射文件 之查询

 <select id="selectStudentConverter" parameterType="Integer" resultMap="selectConverter">
        select * from student where stuno=#{stuno}
    </select>
1.resultMap和resultType的区别

        情况1:如果类中的属性类型和表中的字段类型能够合理的被识别(String-varchar) ,则使用resultType,否则使用resultMap

        情况2:如果类中的属名称和表中的字段名称能够合理的被识别(stuno-stuno) ,则使用resultType,否则使用resultMap

2.配置resultMap(在sql映射文件中配置)
 <resultMap id="selectConverter" type="student">
<!--        分为主键和非主键-->
        <id property="stuNo" column="stuno"></id>
        <result property="stuName" column="stuname"></result>
        <result property="stuAge" column="stuage"></result>
        <result property="graName" column="graname"></result>
        <result property="stuSex" column="stusex" javaType="boolean" jdbcType="Integer"></result>
    </resultMap>
          第一个id:代表通过这个id值可以找到这个map

          第二个id:代表主键

         result:代表非主键

        property:代表java中的属性名

        column:代表数据库的字段名

        javaType:java属性的类型

        jdbcType:数据库字段的类型 并且只能是大写

3.测试查询操作

(4)配置sql映射文件 之增改

<!--    含有类型转换的操作-->
    <insert id="addStudenttConverte" parameterType="org.hbz.entity.Student">
        insert into student(stuName,stuAge,graName,stuSex) values(#{stuName},#{stuAge},#{graName},#{stuSex ,javaType=boolean,jdbcType=INTEGER })
    </insert>

1.在需要转换的地方 #{实体的属性名称,javaType=实体的属性类型,jdbcType数据库的字段的类型}

2.测试结果:

3.#{xx}中存放的属性值 严格区分大小写

课时4:l两种取值符号以及ParameterType为简单,对象,嵌套对象类型

.1)输入参数:ParameterType

1.类型为简单类型(8个基本类型+String)

    1.1${} 和 #{}的区别

    (1)#{任意值}

        ${value},其中的标识符只能是value

    (2)#{}自动给String类加上‘ ’ (自动类型转换)

        ${}原样输出,但是适用于 动态排序(动态字段)

        动态排序的实例:
<!--    动态排序-->
    <select id="selectStudentByOrderBy" parameterType="string" resultType="student">
        select * from student order by ${value} desc
    </select>
    如果使用#{}会自动的添加‘ ‘号 就不符合数据库的语句

        (3) #{}可以防止sql注入

            ${}不防止

2.类型是对象或者是嵌套对象类型

1.对象类型

<!--    通过家庭地址或者学校地址插叙学生-->
    <select id="selectStudentByhomeOrSchool" parameterType="Address" resultType="student">
select stuno,stuName from student where homeaddress=#{homeAddress} or schooladdress='${schoolAddress}'
    </select>

2.嵌套对象类型

 <!--    通过家庭地址或者学校地址插叙学生-->
    <select id="selectStudentByhomeOrSchool" parameterType="student" resultType="student">
select stuno,stuName from student where homeaddress=#{address.homeAddress} or schooladdress='${address.schoolAddress}'
    </select>
(1)#{}${}两个都支持级联  有点像表达式

课时5 入参为HashMap,以及mybatis调用存储过程CRUD

.1) 入参为HashMap

1.创建sql语句

<!--    通过hashMap入参来通过家庭地址或者学校地址插叙学生-->
    <select id="selectStudentByhomeOrSchoolMap" resultType="Student" parameterType="Map">
        select stuno,stuName from student where homeaddress=#{homeAddress} or schooladdress=#{schoolAddress}
    </select>

2.编写接口

    /**
     *
     * @param map
     * @return
     */
    List<Student> selectStudentByhomeOrSchoolMap(Map<String,Object> map);

3.测试类


  public static void selectAllOrderByhomeOrSchoolMap() throws IOException {         
      Reader reader = Resources.getResourceAsReader("config.xml");                  
      SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
      SqlSession session=sessionFactory.openSession();                              
      IStudentDao iStudentDao=session.getMapper(IStudentDao.class);                 
      Map<String,Object> map=new HashMap<>();                                       
      map.put("homeAddress","sy");                                                  
      map.put("schoolAddress","sy");                                                
      List<Student> stus = iStudentDao.selectStudentByhomeOrSchoolMap(map);         
      System.out.println(stus);                                                     
      session.close();                                                              
      reader.close();                                                               
  }
    (1)用map中的key的值  匹配 占位符#{stuAge} ,如果匹配成功,就用map的value替换占位符

.2)mybatis如何调用存储过程

1.示例一:查询某个的学生总数 (可能出现错误)

输入:年级

输出:该年级的总数

(1)在数据库创建存储过程
DELIMITER //
 CREATE PROCEDURE queryByGradeWithProcedure
 (IN gName VARCHAR(30),OUT scount INT)
 BEGIN 
 SELECT COUNT(1) INTO scount  FROM student WHERE graName=gName;
 END //

(2) 如何调用数据库里面的存储过程呢?

<!--    通过调用存储过程 实现查询 ,statementType="CALLABLE"
           存储过程的输入参数一般使用HashMap来传递
-->
     <select id="queryCOuntByGraNameWithProcedure" statementType="CALLABLE" parameterType="HashMap">
        {call queryByGradeWithProcedure( #{gName,mode=IN}, #{scount,mode=OUT,jdbcType=INTEGER})}
    </select>

其中 通过statementType=”CALLABLE” 设置SQL的执行方式是存储过程

存储过程的输入参数是gName 需要通过HashMap来指定

通过HashMap方法的put方法传入输出参数的值,通过HashMap的get方法来获取输出参数的值

要注意jar的问题;

存储过程 无论输入参数是什么值,语法上都需要 用map来传值

(3) 测试类

   public static void selectOneStudentByGraName() throws IOException {
        Reader reader = Resources.getResourceAsReader("config.xml");
        SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession session=sessionFactory.openSession();
        IStudentDao iStudentDao=session.getMapper(IStudentDao.class);
        Map <String,Object> map=new HashMap<>();
        map.put("gName","S2");
        iStudentDao.queryCOuntByGraNameWithProcedure(map);
        //获取存储过程的输出参数
        Object count=map.get("scount");
        System.out.println(count);
        session.close();
        reader.close();
    }

2.示例二:根据学号删除学生

输入:学号

(1)创建存储过程

DELIMITER //
CREATE PROCEDURE deleteStudentByStuno
(IN NO INT )
BEGIN
    DELETE FROM student WHERE stuno=NO;
END //

(2) 调用存储过程

<!--    通过调用存储过程  按照id值删除学号-->
    <delete id="deleteStudentByno" statementType="CALLABLE" parameterType="HashMap">
         {call deleteStudentByStuno( #{no,mode=IN})}
    </delete>

只要是这个事务方式 只要是删除添加更新 都需要手工的提交事务

(3)测试类

  public static void deleteStudentByno() throws IOException {
        Reader reader = Resources.getResourceAsReader("config.xml");
        SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession session=sessionFactory.openSession();
        IStudentDao iStudentDao=session.getMapper(IStudentDao.class);
        Map <String,Object> map=new HashMap<>();
        map.put("no",3);
        iStudentDao.deleteStudentByno(map);
        session.commit();
        session.close();
        reader.close();
    }

课时6 输出参数为简单类型、对象类型、HashMap及resultMap使用

.1)resultType

(1)简单类型(8个基本类型加String)

(2)输出类型为实体对象类型

(3) 输出参数为实体对象类型的集合 :虽然输出类型为集合,但是resultType依然写 集合的元素类型(resultType=”student”)

(4)输出参数为HashMap

<!--    别名作为Map的key-->
    <select id="queryStudentOutHashMap" resultType="HashMap" parameterType="int">
        select stuName "name",stuAge "age" from student where stuno=#{xx}
    </select>
    --HashMap本身就是一个集合,可以存放多个元素,

    但是根据提示发现   返回值为HashMap的时候,查询的结果只能是一个学生(no,name);

结论---》:一个HashMap对应一个学生的多个元素(多个属性) (一个map一个学生)

如果非要改成输出为多个学生 改进如下:

<!--    查询返回值为集合map-->
    <select id="queryAllStudentOutHashMap" resultType="HashMap">
        select stuName "name",stuAge "age" from student
    </select>
 /**
     * 查询所有学生并且返回值为Map集合
     * @return
     */
    List<Map<String ,Object>> queryAllStudentOutHashMap();
   public static void queryAllStudentOutHashMap() throws IOException {
        Reader reader = Resources.getResourceAsReader("config.xml");
        SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession session=sessionFactory.openSession();
        IStudentDao iStudentDao=session.getMapper(IStudentDao.class);
        List<Map<String, Object>> map = iStudentDao.queryAllStudentOutHashMap();
        System.out.println(map);
        session.close();
        reader.close();
    }

.2)resultMap

(1)实体类的属性表中的字段:类型,名字不同时(stuno,id)

注意:当属姓名和字段名不一致时,除了resultMap以外,还可以使用resultType+HashMap

1.resultMap处理属性和字段不一致

<!--    使用resultMap返回-->
    <select id="queryAllStudentByidMap" resultMap="queryAllStudentByidMaps" parameterType="int">
        select id,name from student where id=#{xx}
    </select>

    <resultMap id="queryAllStudentByidMaps" type="student">
        <id property="stuNo" column="id"></id>
        <result property="stuName" column="name"></result>
    </resultMap>

2.resultType处理属性和字段名不一致

<!--使用resultType返回-->
    <select id="queryAllStudentByidWithType" resultType="student" parameterType="int">
        select id "stuNo",name "stuName" from student where id=#{xx}
    </select>

select 表中的字段名 “类中的属性名” from …来指定属性名和字段名的关系

注意:如果10个字段 ,但发现 某一个属性结果始终为默认值(0,0.0,null) ,则可能是表的字段和类的属性 名字写错了

课时7:动语态SQL、foreach、输入参数为集合属性、集合、数组、动态数组

.1)if和where标签的使用

1.第一种方式来来实现动态的sql

<!--    是用if标签实现动态sql语句 1-->
    <select id="queryAllStudentByNameAndAgeSql" resultType="student" parameterType="student">
        select stuno,stuname,stusex from student where 1=1
        <if test="stuSex!=null and stuSex!=''">
                and stusex=#{stuSex}
        </if>
        <if test="stuName!=null and stuName!=''">
             and stuname=#{stuName}
        </if>

2.第二种方式来实现动态sql方式

  <select id="queryAllStudentByNameAndAgeSql" resultType="student" parameterType="student">
        select stuno,stuname,stusex from student
        <where>
        <if test="stuSex!=null and stuSex!=''">
            and stusex=#{stuSex}
        </if>
        <if test="stuName!=null and stuName!=''">
            and stuname=#{stuName}
        </if>
        </where>
    </select>

where:标签可以自动的处理第一个and 但是不会处理其他的and 推荐使用第二种方式

.2)foreach标签的使用

(1) 可以迭代的类型 :数组,对香数组,集合,属性(Grade)类:List ids

如果是类中的集合以下代码就是实例

<!--    通过年纪实体里里面的所有学号来查询学生-->
    <select id="querystuNosInGrade" parameterType="grade" resultType="student">
        select * from student
        <where>
            <if test="nos!=null and nos.size>0">
                <foreach collection="nos" open="and stuno in(" close=")" item="no" separator=",">
                    #{no}
                </foreach>
            </if>
        </where>
    </select>

(2)collection:代表的是要浏览哪个集合

(3)open 在循环值的前半部分的条件sql语句

(4)close 在循环值的后半部分的条件sql语句

(5) item 临时变量 列如一堆学生 这个就代表其中一个

(6) separator 按照什么样的字符分割数据 列如:-,:, ,

(7)取值方式:#{临时变量}

(8如果是简单数组类型:无论编写代码时,传递的是什么参数名,在mapper.xml中 必须使用array来代替该数组

 <!--    通过年纪实体里里面的所有学号来查询学生-->
    <select id="querystuNosInArray" parameterType="int[]" resultType="student">
        select * from student
        <where>
            <if test="array!=null and array.length>0">
                <foreach collection="array" open="and stuno in(" close=")" item="no" separator=",">
                    #{no}
                </foreach>
            </if>
        </where>
    </select>

(9)如果是集合类型:无论编写代码时,传递的是什么参数名,在mapper.xml中 必须使用list来代替该集合

 <select id="querystuNosInList" parameterType="list" resultType="student">
        select * from student
        <where>
            <if test="list!=null and list.size>0">
                <foreach collection="list" open="and stuno in(" close=")" item="no" separator=",">
                    #{no}
                </foreach>
            </if>
        </where>
    </select>

(10)如果是对象数组类型的:第一点——-传递值的时候不必须是Object[]数组 ,第二点——在取值的时候需要用

临时变量.具体的属性名称

<select id="querystuNosInsObject" parameterType="Object" resultType="student">
        select * from student
        <where>
            <if test="array!=null and array.length>0">
                <foreach collection="array" open="and stuno in(" close=")" item="student" separator=",">
                    #{student.stuNo}
                </foreach>
            </if>
        </where>
    </select>

.3)SQL片段

java中的方法

数据库中的存储过程和存储函数

mybatis中的sql片段 mybatis怎么提取公共的sql语句呢

  <sql id="foreachNo">
        <where>
            <if test="array!=null and array.length>0">
                <foreach collection="array" open="and stuno in(" close=")" item="student" separator=",">
                    #{student.stuNo}
                </foreach>
            </if>
        </where>
    </sql>
    <select id="querystuNosInsObject" parameterType="Object" resultType="student">
        select * from student
       <include refid="foreachNo"></include>
    </select>

使用sql标签来创建片段的部分 再用include的refid到映射导入

如果这个片段 不在一个文件中(不在一个空间中) 需要 namespace的值.片段的id来映射导入

设置参数 描述 有效值 默认值
cacheEnabled 该配置影响所有映射器中配置的缓存全局开关 true、 false true
lazyLoadingEnabled 延迟加载的全局开关,当它开启时,所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态 true、false false
aggressiveLazyLoading 当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载 true、 false true
multipleresultSetsEnabled 是否允许单一语句返回多结果集(需要兼容驱动) true、 false true
useColumnLabel 使用列标签代替列名。不同的驱动在这方面会有不同的表现,具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果 true、 false true
useGeneratedKeys 允许JDBC支持自动生成主键,需要驱动兼容。如果设置为true,则这个设置强制使用自动生成主键 true、fase false
autoMappingBehavior 指定 MyBatis应如何自动映射列到字段或属性:NONE表示取消自动映射、PARTIAL只会自动映射没有定义嵌套结果集映射的结果集、FULL会自动映射任意复杂的结果集 NONE、 PARTIAL、FULL PARTIAL
defaultExecutorType 配置默认的执行器:SIMPLE是普通的执行器、REUSE执行器会重用预处理语句(prepared statements)、BATCH执行器将重用语句并执行批量更新 SIMPLE、 REUSE、SIMPLE SIMPLE
defaultStatementTimeout 设置超时时间,它决定驱动等待数据库响应的秒数。当没有设置的时候它取的就是驱动默认的时间 any positive integer Not set(null)
safeRowBoundsEnabled 允许在嵌套语句中使用分页(Row Bounds) true、 false False
mapUnderscoreToCamelCase 是否开启自动驼峰命名规则映射,即从经典数据库列名 A_COLUMN到经典Java属性名 aColumn的类似映射 true、false false
localCacheScope MyBatis利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。若设置值为STATEMENT,本地 STATEMENT会话仅用在语句执行上,对相同 SqlSession的不同调用将不会共享数据 SESSION、STATEMENT SESSION
jdbcTypeForNull 当没有为参数提供特定的JDBC类型时,为空值指定JDBC类型。某些驱动需要指定列的JDBC类型,多数情况情况直接使用一般类型即可,比如NULL、 VARCHAR、OTHER JdbcType枚举 OTHER
lazyLoadTriggerMethods 指定对象的方法触发一次延迟加载 如果是一个方法列表,我们则用逗号将它们隔开 equals, clone, hashCode, toString
defaultScriptingLanguage 指定动态SQL生成的默认语言 你可以配置类的别名或者类的全限定名 org….XMLDynamicLanguageRiver
callSettersOnNulls 指定当结果集中值为null的时候是否调用映射对象的setter(map对象时为put)方法,这对于有Map.keySet()依赖或null值初始化的时候是有用的。注意基本类型是不能设置成null的 true、 false false
logPrefix 指定MyBatis增加到日志名称的前缀 任何字符串 没有设置
logImpl 指定 MyBatis所用日志的具体实现,未指定时将自动查找 SLF4J、LOG4J、JDK LOGGING、NO LOGGING 没有设置
proxyFactory 指定MyBatis创建具有延迟加载能力的对象所用到的代理工具 CGLIB、JAVASSIST (3.3.0以上版本是)JAVASSIST,否则CGLIB

mybatis缓存:

一级缓存: 自动开始,无法关闭.(只在同一个session中生效)
二级缓存:
1 需手动开启. 在总配置文件中开启二级缓存:

2 在具体的XXXMapper.xml文件中添加 手动开启. 可以夸session实现缓存. 如果某一个查询不需要缓存, 可以使用 useCache=”false” 来关闭.