SSM-Mybatis入门学习

一.MyBatis持久层框架

1. 概念

MyBatis的前身就是iBatis,iBatis本是apache的一个开源项目,2010年5月这个项目由apahce sofeware foundation 迁移到了google code,并且改名为MyBatis。

MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。
特点:
1.简化JDBC的开发
2.能够更好的完成ORM(对象关系映射)

2.内部组件结构图

在这里插入图片描述

1.核心配置文件

mybatis-config.xml配置了事务管理,数据源

2.映射文件

XxxMapper.xml 存放大量的CRUD的SQL语句

3.核心工具类

会话工厂SqlSessionFactory : 产生会话
会话SqlSession : 执行SQL语句

4.ORM

是指对象关系映射.
把表里的字段的值 查到 自动交给 类里的属性 保存

3.入门案例

准备库,表,数据
修改pom.xml,添加mybatis的jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cgb2106boot01</artifactId>
        <groupId>cn.tedu</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>day17</artifactId>

    <dependencies>

        <!--mybatis依赖包-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <!--jdbc依赖包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>
创建核心配置文件mybatis_config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
    <!--enviroments可以配置多个数据库的信息,default指定默认的环境-->
    <environments default="test">
        <environment id="test">
            <!--使用的事务管理器-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置了数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai" />
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
</configuration>
创建映射文件UserMapper.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">

<!-- mybatis的核心配置文件 -->
<!--这个文件是映射文件,写SQL的
    namespace用来作为一个mapper.xnl文件的唯一标识
-->
<mapper namespace="userMapper">
    <!--查id=1的用户信息
        id是这条SQL的唯一标识
        resultType的值用来封装查到的结果-ORM
    -->
    <select id = "getById" resultType="cn.tedu.pojo.User">
        select * from user where id = 1;
    </select>
</mapper>
封装pojo类
package cn.tedu.pojo;

//属性的名字  必须  和表里的字段名   一致

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class User {


    private Integer id;
    private String name;
    private  String addr;
    private  Integer age;

}

二.Mybatis入门案例

1.导入mybatis的jar包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cgb2106boot03</artifactId>
        <groupId>cn.tedu</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>day17</artifactId>

    <dependencies>
        <!--mybatis依赖包-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <!--jdbc依赖包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>
    </dependencies>

</project>

2.核心配置文件

<?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">
<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
<!--environments可以配置多个数据库的连接信息,default指定默认的环境-->
    <environments default="test">
        <environment id="test">
            <!--使用的事务管理器-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置了数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai" />
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--引入映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"></mapper>
    </mappers>

</configuration>

3.映射文件

<?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的
    namespace用来作为一个mapper.xml文件的唯一标识
-->
<mapper namespace="userMapper">
    <!-- 查id=1的用户信息
        id是这条SQL的唯一标识
        resultType的值用来封装查到的结果,ORM
    -->
    <select id="getById" resultType="cn.tedu.pojo.User">
        select * from user where id=1
    </select>
</mapper>

4.创建User类

 package cn.tedu.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

//注意:::属性的名 和 表里的字段名 必须一致,否则无法ORM
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class User {
    private Integer id;
    private String name;
    private String addr;
    private Integer age;
}

5.测试类

package cn.tedu.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.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
public class Test1 {
    @Test
    public void get() throws IOException {
        InputStream in = Resources.getResourceAsStream(
                                    "mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder()
                                                        .build(in);
        SqlSession session = factory.openSession();

        Object o = session.selectOne("userMapper.getById");
        //User(id=1, name=hanmeimei, addr=北京, age=28)
        System.out.println(o);
    }
}

6.总结

在这里插入图片描述

三.Mybatis的练习

1.修改映射文件UserMapper.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">

<!--这个文件是映射文件,写SQL的
    namespace用来作为一个mapper.xml文件的唯一标识
-->
<mapper namespace="userMapper">
    <!--
        面试题:SQL动态获取参数时,可以用#或者$
        $ 底层用了低级传输器,可能发生SQL注入攻击,低效,不拼串,可能发生SQL语法错误
        # 底层用了高级传输器,安全,高效,会自动拼接字符串 'xiongda'
    -->
    <!-- 查id=1的用户信息
        id是这条SQL的唯一标识
        resultType的值用来封装查到的结果,ORM
    -->
    <select id="getById" resultType="cn.tedu.pojo.User">
        select * from user where id=${id}
    </select>
    <!-- 查询所有user -->
    <select id="getAll" resultType="cn.tedu.pojo.User">
        select * from user
    </select>
    <!-- 查询hanmeimei的,固定语法#{??}用来解析SQL的参数-->
    <select id="getByName" resultType="cn.tedu.pojo.User">
        select * from user where name=#{name}
    </select>

</mapper>

2.修改测试类

package cn.tedu.test;
import cn.tedu.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Test1 {
    @Test
    public void get() throws IOException {
        //读取配置文件
        InputStream in = Resources.getResourceAsStream(
                                    "mybatis-config.xml");
        //创建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder()
                                                        .build(in);
        //开启会话,准备执行SQL
        SqlSession session = factory.openSession();
        //定位SQL(namespace的值.id的值),并执行
        //selectOne执行查询的SQL,并只会返回一个结果
        Object o = session.selectOne("userMapper.getById",2);
        //User(id=1, name=hanmeimei, addr=北京, age=28)
        System.out.println(o);

        //定位SQL(namespace的值.id的值),并执行
        //selectList执行查询的SQL,并返回多个结果
        List<User> list = session.selectList("userMapper.getAll");
        for(User u : list){
            System.out.println(u);
        }
        //定位SQL(namespace的值.id的值),并执行,并给SQL传入参数
        User u = session.selectOne(
                        "userMapper.getByName","xiongda");
        System.out.println(u);
    }
}

3.总结

在这里插入图片描述
在这里插入图片描述
参数值:paramterType
指定参数类型,通常制定一个对象类型。
返回值:resultType
非常重要的东西,即完成ORM的映射关系所在。这里指定的cd.tedu.mybatis.domain.User代表把结果集转换成一个User对象实例。

返回值:resultMap
resultMap 用于对复杂对象结构时,对应的ResultMap结构名称

#和$的区别(面试题)
两种方式都可以获取参数的值。区别如下:

(推荐!)#: 使用#{parameterName}引用参数的时候,Mybatis会把这个参数认为是一个字符串,例如传入参数是"Smith",那么在SQL(Select * from emp where name = #{employeeName})使用的时候就会转换为Select * from emp where name = ‘Smith’。

在这里插入图片描述
$: 不做字符串拼接,SQL(Select * from emp where name = ${employeeName})使用的时候就会转换为Select * from emp where name = Smith。此时,如果字段是varchar类型直接抛出SQL异常。

在这里插入图片描述
从安全性上考虑,能使用#尽量使用#来传参,因为这样可以有效防止SQL注入的问题。

SQL中有特殊字符
当SQL中有特殊字符,mybatis不能正常解析时,

用<![CDATA[ ?? ]]>括起来就解决了 <![CDATA[ and age<=#{age} ]]>

<![CDATA[
	and age<=#{age}
]]>

where age<10写成 where age &lt;10
在这里插入图片描述

四.优化配置

1.别名:alias

在sqlMapConfig.xml配置,在映射文件中直接写对象名称即可

<typeAliases>
<typeAlias type="cn.mybatis.pojo.User" alias="User"/>
</typeAliases>
修改核心配置文件,加别名的代码
<?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">
<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
    <!--配置别名,给指定类起一个指定的别名-->
    <typeAliases>
        <typeAlias type="cn.tedu.pojo.User" alias="User"></typeAlias>
    </typeAliases>

<!--environments可以配置多个数据库的连接信息,default指定默认的环境-->
    <environments default="test">
        <environment id="test">
            <!--使用的事务管理器-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置了数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb2?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai" />
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--引入映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"></mapper>
    </mappers>

</configuration>

修改映射文件,使用别名
<?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的
    namespace用来作为一个mapper.xml文件的唯一标识
-->
<mapper namespace="userMapper">
    <!--
        面试题:SQL动态获取参数时,可以用#或者$
        $ 底层用了低级传输器,可能发生SQL注入攻击,低效,不拼串,可能发生SQL语法错误
        # 底层用了高级传输器,安全,高效,会自动拼接字符串 'xiongda'
    -->
    <!-- 查id=1的用户信息
        id是这条SQL的唯一标识
        resultType的值用来封装查到的结果,ORM
    -->
    <select id="getById" resultType="User">
        select * from user where id=${id}
    </select>
    <!-- 查询所有user -->
    <select id="getAll" resultType="User">
        select * from user
    </select>
    <!-- 查询hanmeimei的,固定语法#{??}用来解析SQL的参数-->
    <select id="getByName" resultType="User">
        select * from user where name=#{name}
    </select>

</mapper>

五.接口开发

1.概述

为了优化定位SQL的字符串拼接过程,namespace的值,id的值
步骤:
0.创建接口 创建方法
1.namespace的值是接口的全路径
2.id的值,是接口里的方法名

2.使用

需求:查询id=1的部门信息
创建Dept类
package cn.tedu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
//完成ORM,属性名 必须和字段名 一致
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class Dept {
    private Integer id;
    private String dname;
    private String loc;
}

创建DeptMapper.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="deptMapper">

   <select id="getById" resultType="Dept">
       select * from dept where id=1
   </select>

</mapper>

修改核心配置文件,加了别名和引入Mapper
<?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">
<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
    <!--配置别名,给指定类起一个指定的别名-->
    <typeAliases>
        <typeAlias type="cn.tedu.pojo.User" alias="User"></typeAlias>
        <typeAlias type="cn.tedu.pojo.Dept" alias="Dept"></typeAlias>
    </typeAliases>

<!--environments可以配置多个数据库的连接信息,default指定默认的环境-->
    <environments default="test">
        <environment id="test">
            <!--使用的事务管理器-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置了数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb2?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai" />
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--引入映射文件-->
    <mappers>
        <mapper resource="UserMapper.xml"></mapper>
        <mapper resource="DeptMapper.xml"></mapper>
    </mappers>

</configuration>

测试
package cn.tedu.test;
import cn.tedu.pojo.Dept;
import cn.tedu.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Test1 {
    @Test
    public void get() throws IOException {
        //读取配置文件
        InputStream in = Resources.getResourceAsStream(
                                    "mybatis-config.xml");
        //创建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder()
                                                        .build(in);
        //开启会话,准备执行SQL
        SqlSession session = factory.openSession();
        //定位SQL(namespace的值.id的值),并执行
        //selectOne执行查询的SQL,并只会返回一个结果
        Object o = session.selectOne("userMapper.getById",2);
        //User(id=1, name=hanmeimei, addr=北京, age=28)
        System.out.println(o);

        //定位SQL(namespace的值.id的值),并执行
        //selectList执行查询的SQL,并返回多个结果
        List<User> list = session.selectList("userMapper.getAll");
        for(User u : list){
            System.out.println(u);
        }
        //定位SQL(namespace的值.id的值),并执行,并给SQL传入参数
        User u = session.selectOne(
                        "userMapper.getByName","xiongda");
        System.out.println(u);

        //定位SQL(namespace的值.id的值)
        Dept d = session.selectOne("deptMapper.getById");
        System.out.println(d);
        
    }
}

3.改造

创建接口
package cn.tedu.dao;
import cn.tedu.pojo.Dept;
//接口的全路径=映射文件中namespace的值
//接口的方法名=映射文件中id的值
public interface DeptMapper {
    Dept getById();
}
改造映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace=接口的全路径 -->
<mapper namespace="cn.tedu.dao.DeptMapper">
   <!--id=接口里的方法名-->
   <select id="getById" resultType="Dept">
       select * from dept where id=1
   </select>
</mapper>

改造测试类
package cn.tedu.test;
import cn.tedu.dao.DeptMapper;
import cn.tedu.pojo.Dept;
import cn.tedu.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Test1 {
    @Test
    public void get() throws IOException {
        //读取配置文件
        InputStream in = Resources.getResourceAsStream(
                                    "mybatis-config.xml");
        //创建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder()
                                                        .build(in);
        //开启会话,准备执行SQL
        SqlSession session = factory.openSession();
        //定位SQL(namespace的值.id的值),并执行
        //selectOne执行查询的SQL,并只会返回一个结果
        Object o = session.selectOne("userMapper.getById",2);
        //User(id=1, name=hanmeimei, addr=北京, age=28)
        System.out.println(o);

        //定位SQL(namespace的值.id的值),并执行
        //selectList执行查询的SQL,并返回多个结果
        List<User> list = session.selectList("userMapper.getAll");
        for(User u : list){
            System.out.println(u);
        }
        //定位SQL(namespace的值.id的值),并执行,并给SQL传入参数
        User u = session.selectOne(
                        "userMapper.getByName","xiongda");
        System.out.println(u);

        //定位SQL(namespace的值.id的值)
//        Dept d = session.selectOne("deptMapper.getById");
//        System.out.println(d);
        //获取了指定的接口
        DeptMapper mapper = session.getMapper(DeptMapper.class);
        //调用接口里的方法
        Dept dd = mapper.getById();
        System.out.println(dd);
    }
}


总结

在这里插入图片描述

六.练习接口开发

1.修改 接口文件

package cn.tedu.dao;
import cn.tedu.pojo.Dept;

import java.util.List;

//接口的全路径=映射文件中namespace的值
//接口的方法名=映射文件中id的值
public interface DeptMapper {
    Dept getById(); //根据id查
    List<Dept> getByName(String dname);//根据名字查
    void save(Dept dept);//新增部门记录
}

2.修改映射文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace=接口的全路径 -->
<mapper namespace="cn.tedu.dao.DeptMapper">
    <!--新增部门记录-->
    <insert id="save">
        insert into dept values(#{id},#{dname},#{loc})
    </insert>
    <select id="getByName" resultType="Dept">
        select * from dept where dname=#{dname};
    </select>
   <!--id=接口里的方法名-->
   <select id="getById" resultType="Dept">
       select * from dept where id=1
   </select>
</mapper>

3.修改 测试 文件

package cn.tedu.test;
import cn.tedu.dao.DeptMapper;
import cn.tedu.pojo.Dept;
import cn.tedu.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Test1 {
    @Test
    public void get() throws IOException {
        //读取配置文件
        InputStream in = Resources.getResourceAsStream(
                                    "mybatis-config.xml");
        //创建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder()
                                                        .build(in);
        //开启会话,准备执行SQL
        SqlSession session = factory.openSession();
        //定位SQL(namespace的值.id的值),并执行
        //selectOne执行查询的SQL,并只会返回一个结果
        Object o = session.selectOne("userMapper.getById",2);
        //User(id=1, name=hanmeimei, addr=北京, age=28)
        System.out.println(o);

        //定位SQL(namespace的值.id的值),并执行
        //selectList执行查询的SQL,并返回多个结果
        List<User> list = session.selectList("userMapper.getAll");
        for(User u : list){
            System.out.println(u);
        }
        //定位SQL(namespace的值.id的值),并执行,并给SQL传入参数
        User u = session.selectOne(
                        "userMapper.getByName","xiongda");
        System.out.println(u);

        //定位SQL(namespace的值.id的值)
//        Dept d = session.selectOne("deptMapper.getById");
//        System.out.println(d);
        //获取了指定的接口
        DeptMapper mapper = session.getMapper(DeptMapper.class);
        //调用接口里的方法
        Dept dd = mapper.getById();
        System.out.println(dd);

        List<Dept> ds = mapper.getByName("java教研部");
        for (Dept d : ds) {
            System.out.println(d);
        }

        Dept dept = new Dept();
        dept.setId(100).setDname("ios开发部").setLoc("上海");
        mapper.save(dept);
        //mybatis不会自动提交事务,增删改需要自己提交事务
        session.commit();
    }
}

七.动态SQL

1.概述

利用mybatis框架提供一些标签,完成SQL的拼接
利用标签
sql:提取SQL片段,提高SQL的复用.

include:引入指定的SQL片段

<sql id="cols">
id,title,sell_point,price,num,barcode,image,cid,status,created,updated
</sql>

<select id="find" resultType="Item" parameterType="Item">
SELECT <include refid="cols"/> FROM tb_item
</select>

if:用来判断,满足条件才拼接SQL

<select id="find" resultType="Item" parameterType="Item">
SELECT <include refid="cols"/> FROM tb_item where
	<if test="title != null"> title like #{title} </if>
	<if test="sellPoint != null">and sell_point like #{sellPoint}</if>
</select>

2.修改映射文件,实现动态SQL

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace=接口的全路径 -->
<mapper namespace="cn.tedu.dao.DeptMapper">
    <!-- 提取SQL片段,提高SQL片段复用性 -->
    <sql id="cols">
        id,dname,loc
    </sql>
    <!-- 引用SQL片段 -->
    <select id="getByName" resultType="Dept">
        select 
         <include refid="cols"></include>
        from dept
        <if test="dname != null">
            where  dname=#{dname}
        </if>
    </select>
    
   <!--id=接口里的方法名-->
   <select id="getById" resultType="Dept">
       select 
       <include refid="cols"></include>
       from dept where id=1
   </select>

    <!--新增部门记录-->
    <insert id="save">
        insert into dept values(#{id},#{dname},#{loc})
    </insert>
</mapper>

3.foreach标签

在这里插入图片描述

修改映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace=接口的全路径 -->
<mapper namespace="cn.tedu.dao.DeptMapper">
    <!-- 提取SQL片段,提高SQL片段复用性 -->
    <sql id="cols">
        id,dname,loc
    </sql>

    <!-- delete from dept where id in(1,2,3)-->
    <delete id="delete">
        delete from dept where id in(
             /*foreach用来完成遍历
    collection表示要遍历哪种集合里的数据,值是固定值:array/list/Map.key
    item表示即将遍历到的数据,separator是分隔符,#{ids}获取遍历到的数据
             */
            <foreach collection="array" item="ids" separator=",">
                #{ids}
            </foreach>
        )
    </delete>

    <!-- 引用SQL片段 -->
    <select id="getByName" resultType="Dept">
        select 
         <include refid="cols"></include>
        from dept
        <if test="dname != null">
            where  dname=#{dname}
        </if>
    </select>
    
   <!--id=接口里的方法名-->
   <select id="getById" resultType="Dept">
       select 
       <include refid="cols"></include>
       from dept where id=1
   </select>

    <!--新增部门记录-->
    <insert id="save">
        insert into dept values(#{id},#{dname},#{loc})
    </insert>
</mapper>
修改接口文件
package cn.tedu.dao;
import cn.tedu.pojo.Dept;

import java.util.List;

//接口的全路径=映射文件中namespace的值
//接口的方法名=映射文件中id的值
public interface DeptMapper {
    Dept getById(); //根据id查
    List<Dept> getByName(String dname);//根据名字查
    void save(Dept dept);//新增部门记录
    void delete(int[] a);//删除
}

修改测试类
package cn.tedu.test;
import cn.tedu.dao.DeptMapper;
import cn.tedu.pojo.Dept;
import cn.tedu.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Test1 {
    @Test
    public void get() throws IOException {
        //读取配置文件
        InputStream in = Resources.getResourceAsStream(
                                    "mybatis-config.xml");
        //创建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder()
                                                        .build(in);
        //开启会话,准备执行SQL
        SqlSession session = factory.openSession();
        //定位SQL(namespace的值.id的值),并执行
        //selectOne执行查询的SQL,并只会返回一个结果
        Object o = session.selectOne("userMapper.getById",2);
        //User(id=1, name=hanmeimei, addr=北京, age=28)
        System.out.println(o);

        //定位SQL(namespace的值.id的值),并执行
        //selectList执行查询的SQL,并返回多个结果
        List<User> list = session.selectList("userMapper.getAll");
        for(User u : list){
            System.out.println(u);
        }
        //定位SQL(namespace的值.id的值),并执行,并给SQL传入参数
        User u = session.selectOne(
                        "userMapper.getByName","xiongda");
        System.out.println(u);

        //定位SQL(namespace的值.id的值)
//        Dept d = session.selectOne("deptMapper.getById");
//        System.out.println(d);
        //获取了指定的接口
        DeptMapper mapper = session.getMapper(DeptMapper.class);
        //调用接口里的方法
        Dept dd = mapper.getById();
        System.out.println(dd);

        List<Dept> ds = mapper.getByName(null);
        for (Dept d : ds) {
            System.out.println(d+"=================");
        }

        Dept dept = new Dept();
        dept.setId(null).setDname("ios开发部").setLoc("上海");
        mapper.save(dept);
        //mybatis不会自动提交事务,增删改需要自己提交事务
        session.commit();


        mapper.delete(new int[]{103,104});
        session.commit();

    }
}


总结

在这里插入图片描述

八.ResultMap

1.概述

resultType只能完成简单的ORM,只能完成那些 字段名 和 属性名一致的情况
字段名 和 属性名 不一样的情况,resultType必须换成resultMap,否则无法ORM

2.测试

项目结构

在这里插入图片描述

创建了表,加了记录
CREATE TABLE `user_info` (
  `id` int(11) NOT NULL auto_increment,
  `user_name` varchar(20) default NULL,
  `user_addr` varchar(20) default NULL,
  `user_age` int(11) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

修改pom.xml,添加mybatis的jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cgb2106boot03</artifactId>
        <groupId>cn.tedu</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>day19</artifactId>


    <dependencies>
        <!--mybatis依赖包-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <!--jdbc依赖包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>
    </dependencies>
</project>

创建核心配置文件
<?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">
<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
    <!--environments可以配置多个数据库的连接信息,default指定默认的环境-->
    <environments default="test">
        <environment id="test">
            <!--使用的事务管理器-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置了数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb2?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai" />
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!--引入映射文件-->
    <mappers>
        <mapper resource="userInfoMapper.xml"></mapper>
    </mappers>
</configuration>
创建映射文件
<?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="cn.tedu.dao.UserInfoMapper">
    <!-- 查询所有 ,字段名和属性名不一样,resultType换成resultMap
        resultType="cn.tedu.pojo.UserInfo"
    -->
    <!-- ORM:是指把字段的值查到以后  交给 同名属性保存
        使用resultMap: 字段名 和 属性名 不一样
        id是唯一标识  type是类的全路径
    -->
    <resultMap id="abc" type="cn.tedu.pojo.UserInfo">
        <result column="user_name" property="userName"></result>
        <result column="user_addr" property="userAddr"></result>
        <result column="user_age" property="userAge"></result>
    </resultMap>
    <!--resultMap属性是解决了resultType解决不了的问题,引用指定的resultMap-->
    <select id="selectList" resultMap="abc">
        select * from user_info
    </select>

</mapper>

创建接口类
package cn.tedu.dao;

import cn.tedu.pojo.UserInfo;

import java.util.List;

public interface UserInfoMapper {
    List<UserInfo> selectList();//查询所有
}

创建pojo类
package cn.tedu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class UserInfo {
    private Integer id;
    private String userName;
    private String userAddr;
    private Integer userAge;
}
测试
package cn.tedu.test;

import cn.tedu.dao.UserInfoMapper;
import cn.tedu.pojo.UserInfo;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Test1 {
    @Test
    public void all() throws IOException {
        InputStream in = Resources.getResourceAsStream(
                        "mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder()
                                            .build(in);
        //true表示自动提交事务
        SqlSession session = factory.openSession(true);
        //获取指定接口
        UserInfoMapper mapper = session.getMapper(UserInfoMapper.class);
        //调用方法
        List<UserInfo> list = mapper.selectList();
        for (UserInfo uf : list) {
            //UserInfo(id=1, userName=null, userAddr=null, userAge=null)
            System.out.println(uf);
        }
    }

}

总结

在这里插入图片描述

3.优化简化resultmap

第一步:在核心配置文件中开启驼峰规则:
<?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">
<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
    <settings>
        <!--开启驼峰规则,简化resultMap的编写-->
        <setting name="mapUnderscoreToCamelCase" value="true" />
    </settings>


    <!--environments可以配置多个数据库的连接信息,default指定默认的环境-->
    <environments default="test">
        <environment id="test">
            <!--使用的事务管理器-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置了数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb2?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai" />
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--引入映射文件-->
    <mappers>
        <mapper resource="userInfoMapper.xml"></mapper>
    </mappers>
</configuration>

第二步:resultMap标签中添加新属性 autoMapping=“true”

扩展

JDBC和MyBatis的区别?

JDBC是java提供了一套专门用于和数据库对接的api,java.sql.*,其规范了如何和数据库进行对接,实现由各数据库厂商进行各自的实现和扩展。学习JDBC重点在学习如何使用其api。

MyBatis框架是轻量级封装了JDBC,我们已经看不到这些api,连接connection、语句preparedstatement、结果集ResultSet,而关注的是mybatis框架体系如何去使用,一旦写好,我们关注的是java对象。

XML和接口方式的区别?

MyBatis提供了两种操作数据库的方式,一种是通过xml映射文件,一种是通过java的接口类。按面向对象方式更加推荐接口方式,但如果复杂的多表映射,仍然需要使用xml映射文件的ResultMap方式实现。

接口只是假象,其底层仍然是通过xml实现,好不容易实现了一套方式,怎忍丢掉呢?可以做个测试就知道它底层怎么实现的?把xml中的sql删除,它就玩不转了。

接口方式怎么找到xml执行的?

SqlSession的getMapper方法找到类,通过反射可以获取到类的全路径(包名.类名),相加后就定位到某个xml的命名空间namespace,在根据调用的方法去找到xml中某个标签的id属性。从而实现价值接口,调用接口的方法而间接找到xml中的标签,通过解析xml获取这个标签的内容,从而获取到sql语句。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

望山。

谢谢您的打赏!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值