MyBatis学习笔记

84 阅读7分钟

一、MyBatis 框架简介

MyBatis 是一个优秀的基于 java 的持久层框架,内部封装了 jdbc,开发者只需要关注 sql 语句本身,而不需要处理加载驱动、创建连接、创建 statement、关闭连接,资源等繁杂的过程。MyBatis 通过 xml 或注解两种方式将要执行的各种 sql 语句配置起来,并通过 java 对象和 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。 MyBatis减轻使用 JDBC 的复杂性,不用编写重复的创建 Connetion , Statement ; 不用编写关闭资源代码。直接使用 java 对象,表示结果数据。让开发者专注 SQL 的处理。 其他分心的工作由 MyBatis 代劳。

二、Mybatis基本的使用流程

2.1创建maven工程,导入对于的maven依赖

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
    <!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.9</version>
    </dependency>
  </dependencies>

  <build>
    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
  </build>

2.2编写实体类,这里以Student类为例

public class Student {
    //定义属性, 目前要求是属性名和列名一样。
    private Integer id;
    private String name;
    private String email;
    private Integer age;

    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 String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getAge() {
        return age;
    }

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

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

2.3编写 Dao 接口 StudentDao

//接口操作student表
public interface StudentDao {

    //查询student表的所有的数据
    public List<Student> selectStudents();

    //插入方法
    //参数: student ,表示要插入到数据库的数据
    //返回值: int , 表示执行insert操作后的 影响数据库的行数
    public int insertStudent(Student student);
}

2.4编写 Dao 接口 Mapper 映射文件 StudentDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjpowernode.dao.StudentDao">
    <!--
       select:表示查询操作。
       id: 你要执行的sql语法的唯一标识, mybatis会使用这个id的值来找到要执行的sql语句
           可以自定义,但是要求你使用接口中的方法名称。

       resultType:表示结果类型的, 是sql语句执行后得到ResultSet,遍历这个ResultSet得到java对象的类型。
          值写的类型的全限定名称
    -->
    <select id="selectStudents" resultType="com.bjpowernode.domain.Student" >
        select id,name,email,age from student order by id
    </select>

    <!--插入操作-->
    <insert id="insertStudent">
        insert into student values(#{id},#{name},#{email},#{age})
    </insert>
</mapper>

2.5创建 MyBatis 主配置文件

==ps:支持中文的url:== ==jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8==

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!--settings:控制mybatis全局行为-->
    <settings>
        <!--设置mybatis输出日志-->
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>

    <!--环境配置: 数据库的连接信息
        default:必须和某个environment的id值一样。
        告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库
    -->
    <environments default="mybatis1">
        <!-- environment : 一个数据库信息的配置, 环境
             id:一个唯一值,自定义,表示环境的名称。
        -->
        <environment id="mybatis1">
            <!--
               transactionManager :mybatis的事务类型
                   type: JDBC(表示使用jdbc中的Connection对象的commit,rollback做事务处理)
            -->
            <transactionManager type="JDBC"/>
            <!--
               dataSource:表示数据源,连接数据库的
                  type:表示数据源的类型, POOLED表示使用连接池
            -->
            <dataSource type="POOLED">
                <!--
                   driver, user, username, password 是固定的,不能自定义。
                -->
                <!--数据库的驱动类名-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--连接数据库的url字符串-->
                <property name="url" value="jdbc:mysql://localhost:3306/db_mybatis"/>
                <!--访问数据库的用户名-->
                <property name="username" value="root"/>
                <!--密码-->
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
        
    </environments>

    <!-- sql mapper(sql映射文件)的位置-->
    <mappers>
        <!--一个mapper标签指定一个文件的位置。
           从类路径开始的路径信息。  target/clasess(类路径)
        -->
        <mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
        <!--<mapper resource="com/bjpowernode/dao/SchoolDao.xml" />-->
    </mappers>
</configuration>

2.6创建测试类

public class MyTest {
    //测试方法,测试功能
    @Test
    public void testInsert() throws IOException {

        //访问mybatis读取student数据
        //1.定义mybatis主配置文件的名称, 从类路径的根开始(target/clasess)
        String config="mybatis.xml";
        //2.读取这个config表示的文件
        InputStream in = Resources.getResourceAsStream(config);
        //3.创建了SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder builder  = new SqlSessionFactoryBuilder();
        //4.创建SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(in);
        //5.获取SqlSession对象,从SqlSessionFactory中获取SqlSession
        //SqlSession sqlSession = factory.openSession();设置为true则为自动提交,则需要第8步
        SqlSession sqlSession = factory.openSession(true);
        //6.【重要】指定要执行的sql语句的标识。  sql映射文件中的namespace + "." + 标签的id值
        String sqlId = "com.bjpowernode.dao.StudentDao.insertStudent";
        //7. 重要】执行sql语句,通过sqlId找到语句
        Student student  = new Student();
        student.setId(1006);
        student.setName("关羽");
        student.setEmail("guanyu@163.com");
        student.setAge(20);
        int nums = sqlSession.insert(sqlId,student);

        //8.mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手工提交事务
        //sqlSession.commit();

        //8.输出结果
        System.out.println("执行insert的结果="+nums);

        //9.关闭SqlSession对象
        sqlSession.close();
    }
}

三、Mybatis基本对象的简要分析

3.1Resources 类

Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返 回不同类型的 IO 流对象。

3.2SqlSessionFactoryBuilder 类

SqlSessionFactory 的 创 建 , 需 要 使 用 SqlSessionFactoryBuilder 对 象 的 build() 方 法 。 由 于 SqlSessionFactoryBuilder 对象在创建完工厂对象后,就完成了其历史使命,即可被销毁。所以,一般会将该 SqlSessionFactoryBuilder 对象创建为一个方法内的局部对象,方法结束,对象销毁。

3.3SqlSessionFactory 接口

SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用 只需要一个该对象即可。创建 SqlSession 需要使用 SqlSessionFactory 接口的的 openSession()方法。 openSession(true):创建一个有自动提交功能的 SqlSession openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交 openSession():同openSession(false)

3.4SqlSession 接口

SqlSession 接口对象用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,一次会话以 SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束。 SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将 其关闭。再次需要会话,再次创建。 SqlSession 在方法内部创建,使用完毕后关闭。

3.5Mybatis优化,创建MyBatisUtil类

通过以上的分析,我们在使用Mybatis时不需要创建很多的以上的类,容易造成浪费,因此我们一般会将以上操作打包生成对应的Util类

MyBatisUtil类代码
public class MyBatisUtils {

    private  static  SqlSessionFactory factory = null;
    static {
        String config="mybatis.xml"; // 需要和你的项目中的文件名一样
        try {
            InputStream in = Resources.getResourceAsStream(config);
            //创建SqlSessionFactory对象,使用SqlSessionFactoryBuild
            factory = new SqlSessionFactoryBuilder().build(in);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //获取SqlSession的方法
    public static SqlSession getSqlSession() {
        SqlSession sqlSession  = null;
        if( factory != null){
            sqlSession = factory.openSession();// 非自动提交事务
        }
        return sqlSession;
    }
}
MyBatisUtil工具类的使用
public class MyApp2 {
    public static void main(String[] args) throws IOException {
        //获取SqlSession对象,从SqlSessionFactory中获取SqlSession
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        //【重要】指定要执行的sql语句的标识。  sql映射文件中的namespace + "." + 标签的id值
        String sqlId = "com.bjpowernode.dao.StudentDao.selectStudents";
        //【重要】执行sql语句,通过sqlId找到语句
        List<Student> studentList = sqlSession.selectList(sqlId);
        //输出结果
        studentList.forEach( stu -> System.out.println(stu));
        //关闭SqlSession对象
        sqlSession.close();
    }
}

四、Mybatis之使用Dao实现类方式操作数据库

4.1创建Dao接口实现类并实现接口对应方法

public class StudentDaoImpl implements StudentDao {
    @Override
    public List<Student> selectStudents() {
        //获取SqlSession对象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        String sqlId="com.bjpowernode.dao.StudentDao.selectStudents";
        //执行sql语句, 使用SqlSession类的方法
        List<Student> students  = sqlSession.selectList(sqlId);
        //关闭
        sqlSession.close();
        return students;
    }
    @Override
    public int insertStudent(Student student) {
        //获取SqlSession对象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        String sqlId="com.bjpowernode.dao.StudentDao.insertStudent";
        //执行sql语句, 使用SqlSession类的方法
        int nums = sqlSession.insert(sqlId,student);
        //提交事务
        sqlSession.commit();
        //关闭
        sqlSession.close();
        return nums;
    }
}

4.2编写测试类

public class TestMyBatis {
    @Test
    public void testInsertStudent(){
        StudentDao dao  = new StudentDaoImpl();
        Student student = new Student();
        student.setId(1005);
        student.setName("盾山");
        student.setEmail("dunshan@qq.com");
        int nums = dao.insertStudent(student);
        System.out.println("添加对象的数量:"+nums);
    }

}

4.3Mybatis之Dao实现的分析

在上述例子中自定义 Dao 接口实现类时发现一个问题:Dao 的实现类其实并没有干什么实质性的工 作,它仅仅就是通过 SqlSession 的相关 API 定位到映射文件 mapper 中相应 id 的 SQL 语句,真正对 DB 进行操作的工作其实是由框架通过 mapper 中的 SQL 完成的。 所以,MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句,对 DB 进行操作。这种对 Dao 的实现方式称为 Mapper 的动态代理方式。 Mapper 动态代理方式无需程序员实现 Dao 接口。接口是由 MyBatis 结合映射文件自动生成的动态代 理实现的。

五、Mybatis之使用Mapper 的动态代理方式

5.1去除对应的Dao实现类

5.2测试类,直接通过getMapper动态获取对应Dao实现类

代码示例:

public class TestMyBatis {

    @Test
    public void testSelectStudents(){
        /**
         * 使用mybatis的动态代理机制, 使用SqlSession.getMapper(dao接口)
         * getMapper能获取dao接口对于的实现类对象。
         */
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        StudentDao dao  =  sqlSession.getMapper(StudentDao.class);

        //com.sun.proxy.$Proxy2 : jdk的动态代理
        System.out.println("dao="+dao.getClass().getName());
        //调用dao的方法, 执行数据库的操作
        List<Student> students = dao.selectStudents();
        for(Student stu: students){
            System.out.println("学生="+stu);
        }
    }

    @Test
    public void testInsertStudent(){
        SqlSession sqlSession  = MyBatisUtils.getSqlSession();
        StudentDao dao  =  sqlSession.getMapper(StudentDao.class);

        Student student = new Student();
        student.setId(1007);
        student.setName("李飞");
        student.setEmail("dunshan@qq.com");
        student.setAge(28);
        int nums = dao.insertStudent(student);
        sqlSession.commit();
        System.out.println("添加对象的数量:"+nums);
    }

}

六、Mybatis之参数传递

6.1一个简单参数

如果只有一个参数,名称可以随便起,框架会自动调用对于的方法

例如:
public interface StudentDao {
    public Student selectStudent(int id);//参数名称为id
}
    <!--这里的id名称可以随便取,可以和参数名称不一样-->
    <select id="selectStudent" resultType="com.mybatis.www.domain.Student">
        SELECT id, name, email, age FROM student WHERE id = #{idname}
    </select>

6.2多个简单参数

当 Dao 接口方法多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名”), mapper 文件使用#{自定义参数名}。

例如:
//接口方法:
List<Student> selectMultiParam(@Param("personName") String name,
 @Param("personAge") int age);
<!--mapper 文件:-->
<select id="selectMultiParam" resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student where name=#{personName} or age 
=#{personAge}
</select>
//测试方法:
@Test
public void testSelectMultiParam(){
 List<Student> stuList = studentDao.selectMultiParam("李力",20);
 stuList.forEach( stu -> System.out.println(stu));
}

6.3多个参数使用对象

使用 java 对象传递参数, java 的属性值就是 sql 需要的参数值。 每一个属性就是一个参数。语法格式: #{ property,javaType=java 中数据类型名,jdbcType=数据类型名称 }javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。常用格式 #{ property }

==常见使用方式,sql语句中直接使用对象的属性名称==

接口方法:

List<Student> selectMultiObject(QueryParam queryParam);

mapper 文件:

<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student where name=#{queryName} or age 
=#{queryAge}
</select>
<!--或-->
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student
 where name=#{queryName,javaType=string,jdbcType=VARCHAR}
 or age =#{queryAge,javaType=int,jdbcType=INTEGER}
</select>

6.4多个参数按照位置调用

参数位置从 0 开始, 引用参数语法 #{ arg 位置 } , 第一个参数是#{arg0}, 第二个是#{arg1} 注意:mybatis-3.3 版本和之前的版本使用#{0},#{1}方式, 从 mybatis3.4 开始使用#{arg0}方式。

接口方法:

List<Student> selectByNameAndAge(String name,int age);

mapper 文件

<select id="selectByNameAndAge" resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student where name=#{arg0} or age =#{arg1}
</select>

测试方法:

@Test
public void testSelectByNameAndAge(){
 //按位置参数 
 List<Student> stuList = studentDao.selectByNameAndAge("李力",20);
 stuList.forEach( stu -> System.out.println(stu));
}

6.5多个参数使用Map

Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。Map 集合使用 String的 key, Object 类型的值存储参数。 mapper 文件使用 # { key } 引用参数值。

例如:

Map<String,Object> data = new HashMap<String,Object>();
data.put(“myname”,”李力”);
data.put(“myage”,20);

接口方法:

List<Student> selectMultiMap(Map<String,Object> map);

mapper 文件:

<select id="selectMultiMap" resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student where name=#{myname} or age =#{myage}
</select>

测试方法:

@Test
public void testSelectMultiMap(){
 Map<String,Object> data = new HashMap<>();
 data.put("myname","李力");// #{myname}
 data.put("myage",20); // #{myage}
 List<Student> stuList = studentDao.selectMultiMap(data);
 stuList.forEach( stu -> System.out.println(stu));
}

6.6#和$分析

#:占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替 sql 语句的“?”。这样做更安全,更迅速,通常也是==首选==做法,

字符串替换,告诉mybatis使用 字符串替换,告诉 mybatis 使用包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的 内容连接起来。主要用在替换表名,列名,不同==列排序==等操作。

七、Mybatis之返回值

resultType: 执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。 注意如果返回的是集 合,那应该设置为集合包含的类型,而不是集合本身。resultType 和 resultMap,不能同时使用。

7.1简单类型

mapper 文件:

<select id="countStudent" resultType="int">
 select count(*) from student
</select>

测试方法:

@Test
public void testRetunInt(){
 int count = studentDao.countStudent();
 System.out.println("学生总人数:"+ count);
}

7.2对象类型

框架的处理: 使用构造方法创建对象。调用 setXXX 给属性赋值 ==注意:Dao 接口方法返回是集合类型,需要指定集合中的类型,不是集合本身。==

接口方法:

Student selectById(int id);

mapper 文件:

<select id="selectById" resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student where id=#{studentId}
</select>

7.3Map类型

sql 的查询结果作为 Map 的 key 和 value。推荐使用 Map<Object,Object>。 注意:Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。大于一条记录是错误。

接口方法:

Map<Object,Object> selectReturnMap(int id);

mapper 文件:

<select id="selectReturnMap" resultType="java.util.HashMap">
 select name,email from student where id = #{studentId}
</select>

测试方法:

@Test
public void testReturnMap(){
 Map<Object,Object> retMap = studentDao.selectReturnMap(2);
 System.out.println("查询结果是 Map:"+retMap);
}

测试结果示例:

map=={name=李四, id=2, email=lisi@qq.com}

7.4resultMap

resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性。 常用在列名和 java 对象属性名不一样的情况。 使用方式: 1.先定义 resultMap,指定列名和属性的对应关系。 2.在"select"中把 resultType 替换为 resultMap。

接口方法:

List<Student> selectUseResultMap(QueryParam param);

mapper 文件:

<!-- 创建 resultMap
 id:自定义的唯一名称,在<select>使用
 type:期望转为的 java 对象的全限定名称或别名 
-->
<resultMap id="studentMap" type="com.bjpowernode.domain.Student">
 <!-- 主键字段使用 id -->
 <id column="id" property="id" />
 <!--非主键字段使用 result-->
 <result column="name" property="name"/>
 <result column="email" property="email" />
 <result column="age" property="age" />
</resultMap>
<!--resultMap: resultMap 标签中的 id 属性值-->
<select id="selectUseResultMap" resultMap="studentMap">
 select id,name,email,age from student where name=#{queryName} or 
age=#{queryAge}
</select>

测试方法:

@Test
public void testSelectUseResultMap(){
 QueryParam param = new QueryParam();
 param.setQueryName("李力");
 param.setQueryAge(20);
 List<Student> stuList = studentDao.selectUseResultMap(param);
 stuList.forEach( stu -> System.out.println(stu));
}

7.5实体类属性名和列名不同的处理方式

1.使用as方法

/**
* <p>Description: 实体类 </p>
* <p>Company: http://www.bjpowernode.com
*/
public class PrimaryStudent {
 private Integer stuId;
 private String stuName;
 private Integer stuAge;
 // set , get 方法
}
// 接口方法
List<PrimaryStudent> selectUseFieldAlias(QueryParam param);
<!--mapper 文件:-->
<select id="selectUseFieldAlias" 
resultType="com.bjpowernode.domain.PrimaryStudent">
 select id as stuId, name as stuName,age as stuAge
 from student where name=#{queryName} or age=#{queryAge}
</select>
//测试方法
@Test
public void testSelectUseFieldAlias(){
 QueryParam param = new QueryParam();
 param.setQueryName("李力");
 param.setQueryAge(20);
 List<PrimaryStudent> stuList;
 stuList = studentDao.selectUseFieldAlias(param);
 stuList.forEach( stu -> System.out.println(stu));
}

2.使用resultMap方法

7.6模糊查询like使用

模糊查询的实现有两种方式, 一是 java 代码中给查询数据加上“%” ; 二是在 mapper 文件 sql 语句的 条件位置加上“%”

7.6.1 java 代码中给查询数据加上%示例:

//接口方法:
List<Student> selectLikeFirst(String name);
<!--mapper 文件:-->
<select id="selectLikeFirst" resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student
 where name like #{studentName}
</select>
//测试方法:
@Test
public void testSelectLikeOne(){
 String name="%力%";
 List<Student> stuList = studentDao.selectLikeFirst(name);
 stuList.forEach( stu -> System.out.println(stu));
}

7.6.2 sql中给查询数据加上%示例:

//接口方法:
List<Student> selectLikeSecond(String name);
<!--mapper 文件:-->
<select id="selectLikeSecond" resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student
 where name like "%" #{studentName} "%"
</select>
//测试方法:
@Test
public void testSelectLikeSecond(){
 String name="力";
 List<Student> stuList = studentDao.selectLikeSecond(name);
 stuList.forEach( stu -> System.out.println(stu));
}

八、Mybatis之动态SQL

动态 SQL,通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接 SQL 语句。这里的条件判 断使用的表达式为 OGNL 表达式。常用的动态 SQL 标签有、、、等。 MyBatis 的动态 SQL 语句,与 JSTL 中的语句非常相似。 动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询。提交的查询条件不同,执行的 SQL 语句不同。若将每种可能的情况均逐一列出,对所有条件进行排列组合,将会出现大量的 SQL 语句。此时,可使用动态 SQL 来解决这样的问题

在 mapper 的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等符号,最好将其转换为实体符号。否则,XML 可能会出现解析出错问题。

8.1动态 SQL-if

<!--mapper 文件:-->
<!--对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。
语法:<if test=”条件”> sql 语句的部分 </if> -->
<select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student
 where 1=1
 <if test="name != null and name !='' ">
 and name = #{name}
 </if>
 <if test="age > 0 ">
 and age &gt; #{age}
 </if>
</select>

8.2动态 SQL-where

<if/>标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句。因为,若 where 后
的所有<if/>条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 whereSQL
出错。所以,在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生。但当数据量很大时,会
严重影响查询效率。
使用<where/>标签,在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加
where 子句。需要注意的是,第一个<if/>标签中的 SQL 片断,可以不包含 and。不过,写上 and 也不错,
系统会将多出的 and 去掉。但其它<if/>SQL 片断的 and,必须要求写上。否则 SQL 语句将拼接出错。
语法:<where> 其他动态 sql </where>
<!--mapper 文件:-->
<select id="selectStudentWhere" resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student
 <where>
 <if test="name != null and name !='' ">
 and name = #{name}
 </if>
 <if test="age > 0 ">
 and age &gt; #{age}
 </if>
 </where>
</select>

8.3动态 SQL-foreach

<foreach/>标签用于实现对于数组与集合的遍历。对其使用,需要注意:
 collection 表示要遍历的集合类型, list ,array 等。
openclose、separator 为对遍历内容的 SQL 拼接。
语法:
<foreach collection="集合类型" open="开始的字符" close="结束的字符" 
item="集合中的成员" separator="集合成员之间的分隔符">
 #{item 的值}
</foreach>
遍历 List<简单类型>代码示例:

表达式中的 List 使用 list 表示,其大小使用 list.size 表示。 需求:查询学生 id 是 1002,1005,1006

//接口方法:
List<Student> selectStudentForList(List<Integer> idList);
<!--mapper 文件:-->
<select id="selectStudentForList" 
resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student
 <if test="list !=null and list.size > 0 ">
 where id in
 <foreach collection="list" open="(" close=")" 
item="stuid" separator=",">
 #{stuid}
 </foreach>
 </if>
</select>
遍历 List<对象类型>代码示例:
接口方法:
List<Student> selectStudentForList2(List<Student> stuList);
mapper 文件:
<select id="selectStudentForList2" 
resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student
 <if test="list !=null and list.size > 0 ">
 where id in
 <foreach collection="list" open="(" close=")" 
item="stuobject" separator=",">
 #{stuobject.id}
 </foreach>
 </if>
</select>
测试方法:
@Test
public void testSelectForList2() {
 List<Student> list = new ArrayList<>();
 Student s1 = new Student();
 s1.setId(1002);
 list.add(s1);
 s1 = new Student();
 s1.setId(1005);
 list.add(s1);
 List<Student> studentList = studentDao.selectStudentForList2(list);
 studentList.forEach( stu -> System.out.println(stu));
}

8.4动态 SQL之代码片段

//用法:
//<sql/>标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使用该 SQL 片断,需要使用
//<include/>子标签。该<sql/>标签可以定义 SQL 语句中的任何部分,所以<include/>子标签可以放在动态 SQL
//的任何位置

//接口方法:
List<Student> selectStudentSqlFragment(List<Student> stuList);
<!--mapper 文件:-->
<!--创建 sql 片段 id:片段的自定义名称--> <sql id="studentSql">
 select id,name,email,age from student
</sql> <select id="selectStudentSqlFragment" 
resultType="com.bjpowernode.domain.Student">
 <!-- 引用 sql 片段 -->
 <include refid="studentSql"/>
 <if test="list !=null and list.size > 0 ">
 where id in
 <foreach collection="list" open="(" close=")" 
item="stuobject" separator=",">
 #{stuobject.id}
 </foreach>
 </if>
</select>

九、Mybatis配置文件中常见的配置

9.1 主配置文件

项目中使用的 mybatis.xml 是主配置文件。 主配置文件特点:

  1. 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">

9.2 dataSource 标签

Mybatis 中访问数据库,可以连接池技术,但它采用的是自己的连接池技术。在 Mybatis 的 mybatis.xml 配置文件中,通过来实现 Mybatis 中连接池的配置。

Mybatis 将数据源分为三类:

  1. UNPOOLED 不使用连接池的数据源
  2. POOLED 使用连接池的数据源
  3. JNDI 使用 JNDI 实现的数据源

9.2.1dataSource 配置

在 MyBatis.xml 主配置文件,配置 dataSource:

<dataSource type="POOLED">
 <!--连接数据库的四个要素-->
 <property name="driver" value="com.mysql.jdbc.Driver"/>
 <property name="url" 
value="jdbc:mysql://localhost:3306/ssm?charset=utf-8"/>
 <property name="username" value="root"/>
 <property name="password" value="123456"/>
</dataSource>

MyBatis 在初始化时,根据的 type 属性来创建相应类型的的数据源 DataSource,即: type=”POOLED”:MyBatis 会创建 PooledDataSource 实例(一般使用这个) type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例 type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用

9.3 事务

9.3.1默认需要手动提交事务

Mybatis 框架是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的 Connection 对象的 commit(), rollback() 。 Connection 对象的 setAutoCommit()方法来设置事务提交方式的。自动提交和手工提交、 该标签用于指定 MyBatis所使用的事务管理器。MyBatis 支持两种事务管理器类型:JDBC 与 MANAGED。

JDBC:

使用 JDBC 的事务管理机制。即,通过 Connection 的 commit()方法提交,通过 rollback()方法 回滚。但默认情况下,MyBatis 将自动提交功能关闭了,改为了手动提交。即程序中需要显式的对 事务进行提交或回滚。从日志的输出信息中可以看到。

MANAGED:

由容器来管理事务的整个生命周期(如 Spring 容器)。

9.3.2自动提交事务

设置自动提交的方式,factory 的 openSession() 分为有参数和无参数的。有参数为 true,使用自动提交,可以修改 MyBatisUtil 的 getSqlSession()方法。 session = factory.openSession(true); 再执行 insert 操作,无需执行 session.commit(),事务是自动提交的

9.3.3使用数据库属性配置文件

为了方便对数据库连接的管理,DB 连接四要素数据一般都是存放在一个专门的属性文件中的。MyBatis主配置文件需要从这个属性文件中读取这些数据。

使用步骤:

  1. 在 classpath 路径下,创建 properties 文件,例如取名jdbc.properties,具体内容如下
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springdb
jdbc.user=root
jdbc.passwd=123456
  1. 使用 properties 标签,修改主配置文件,文件开始位置加入:
    <!--指定properties文件的位置,从类路径根开始找文件-->
    <properties resource="jdbc.properties" />
  1. 使用 key 指定值
            <dataSource type="POOLED">
                <!--数据库的驱动类名-->
                <property name="driver" value="${jdbc.driver}"/>
                <!--连接数据库的url字符串-->
                <property name="url" value="${jdbc.url}"/>
                <!--访问数据库的用户名-->
                <property name="username" value="${jdbc.user}"/>
                <!--密码-->
                <property name="password" value="${jdbc.passwd}"/>
            </dataSource>

9.4 别名

Mybatis 支持默认别名,我们也可以采用自定义别名方式来开发,主要使用在select resultType=”别名”

    <!--定义别名-->
    <typeAliases>
        <!--
            第一种方式:
            可以指定一个类型一个自定义别名
            type:自定义类型的全限定名称
            alias:别名(短小,容易记忆的)
        -->
        <!--<typeAlias type="com.bjpowernode.domain.Student" alias="stu" />
        <typeAlias type="com.bjpowernode.vo.ViewStudent" alias="vstu" />-->

        <!--
          第二种方式
          <package> name是包名, 这个包中的所有类,类名就是别名(类名不区分大小写)
        -->
        <package name="com.bjpowernode.domain"/>
        <package name="com.bjpowernode.vo"/>
    </typeAliases>

9.5mapper 文件

<!-- sql mapper(sql映射文件)的位置-->
    <mappers>
        <!--第一种方式:指定多个mapper文件-->
        <!--<mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
        <mapper resource="com/bjpowernode/dao/OrderDao.xml" />-->

        <!--第二种方式: 使用包名
            name: xml文件(mapper文件)所在的包名, 这个包中所有xml文件一次都能加载给mybatis
            使用package的要求:
             1. mapper文件名称需要和接口名称一样, 区分大小写的一样
             2. mapper文件和dao接口需要在同一目录
        -->
        <package name="com.bjpowernode.dao"/>
       <!-- <package name="com.bjpowernode.dao2"/>
        <package name="com.bjpowernode.dao3"/>-->
    </mappers>

十、Mybatis配置文件中常见的配置

10.1 Mybatis 通用分页插件

github.com/pagehelper/…

10.2基于 PageHelper 分页

10.2.1maven 坐标

<!--在<environments>之前加入-->
<dependency>
 <groupId>com.github.pagehelper</groupId>
 <artifactId>pagehelper</artifactId>
 <version>5.1.10</version>
</dependency> 

10.2.2加入 plugin 配置

<plugins>
 <plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins> 

10.2.3PageHelper 对象

查询语句之前调用 PageHelper.startPage 静态方法。除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个方法后的第一个 MyBatis 查询方法会被进行分页。

@Test
public void testSelect() throws IOException {
//获取第 1 页,3 条内容
PageHelper.startPage(1,3);
 List<Student> studentList = studentDao.selectStudents();
 studentList.forEach( stu -> System.out.println(stu));
}