MyBatis基础学习知识点2

13 篇文章 0 订阅
5 篇文章 0 订阅

本文衔接MyBatis基础学习知识点1,继续对以下两个问题进行探讨

        1.dao配置文件主要是用来干什么的?如何进行配置?

        2.使用测试方法测试程序运行是如何实现的?每条语句起什么作用?

目录

dao配置文件主要是用来干什么的?如何进行配置?

mapper标签

select标签

insert标签

update标签

delete标签

使用测试方法测试程序运行是如何实现的?每条语句起什么作用?

基础步骤

SqlSessionFactory接口

SqlSession接口

MybatisUtils工具类

实现dao接口

使用代理模式

mybatis的dao代理

理解参数

parameterType

传递一个简单类型参数

传递多个简单类型参数

使用实体类属性传递参数

按照位置传递参数

使用map传参

#占位符与$占位符的区别

封装MyBatis输出结果

resultType

当查询结果为自定义类型时

当查询的结果为简单类型时

当查询结果为Map类型时

resultMap自定义查找结果

有关like查询


dao配置文件主要是用来干什么的?如何进行配置?

        我们拿出一个最简单的dao层配置文件进行分析

<?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.ling.mybatis.dao.UserDao">
    <!--路径的各个包之间必须用.隔开-->
    <select id="findAllUser" resultType="com.ling.mybatis.pojo.User">
        select * from user
    </select>
</mapper>

        可以看到配置文件标签体都在http://mybatis.org/dtd/mybatis-3-mapper.dtd的约束下

其中最为核心的就是mapper标签

mapper标签

        mapper标签用于配置dao接口的相关映射

namespace属性

        用于定义访问sql语句的命名空间,我们在书写最终执行代码的时候可以看到

@Test
    public void test1() throws IOException {
        //定义mybatis核心配置文件在classes下的路径
        String mybatisPath = "mybatisConfig.xml";
        //根据路径获取字节输入流对象
        InputStream is = Resources.getResourceAsStream(mybatisPath);
        //创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //通过SqlSessionFactoryBuilder对象的build方法创建SqlSessionFactory对象
        SqlSessionFactory factory = sqlSessionFactoryBuilder.build(is);
        //通过工厂类的openSession方法获取sql执行对象
        SqlSession sqlSession = factory.openSession();
        //sql执行对象的selectOne方法
        //获取第一个参数,即执行id:由namespace + . + SQL语句标签id
        String id = "com.ling.mybatis.dao.UserDao" + "." + "findUserById";
        User user = sqlSession.selectOne(id);
        System.out.println(user);
        //关闭sqlSession
        sqlSession.close();
    }

        最终sql语句会由SqlSession对象执行,当sql语句执行时需要传入一个字符串,该字符串就时由命名空间和sql语句id构成,如此书写可以让程序更具格式化,层次分明。

        namespace的值建议设置为dao接口在src下的全路径名称,为了方便分清结构层次,以及后续工具的使用,作用是参与识别sql语句的作用。

select标签

        主要用于书写select相关sql语句

id属性

        设置sql语句名称,为了方便分清结构层次,以及后续工具的使用建议使用对应的方法名称

resultType属性

        设置查找到的最终结果的返回值类型,类型需要写src下的全路径名称

例如:

    <select id="findAllUser" resultType="com.ling.mybatis.pojo.User">
        select * from user
    </select>

insert标签

        主要用于书写insert相关sql语句

id属性

        设置sql语句名称,为了方便分清结构层次,以及后续工具的使用建议使用对应的方法名称

<insert id="insertUser">
    insert into user values(#{id},#{username},#{password})
</insert>

update标签

        主要用于书写update相关sql语句

id属性

        设置sql语句名称,为了方便分清结构层次,以及后续工具的使用建议使用对应的方法名称

    <update id="updateUser">
        update user set password = #{password} WHERE id = #{id};
    </update>

delete标签

        主要用于书写delete相关sql语句

id属性

        设置sql语句名称,为了方便分清结构层次,以及后续工具的使用建议使用对应的方法名称

    <delete id="deleteUser">
        delete from user where id = #{id}
    </delete>

使用测试方法测试程序运行是如何实现的?每条语句起什么作用?

        首先我们使用以下基础执行代码作为例子进行说明

@Test
    public void test1() throws IOException {
        //定义mybatis核心配置文件在classes下的路径
        String mybatisPath = "mybatisConfig.xml";
        //根据路径获取字节输入流对象
        InputStream is = Resources.getResourceAsStream(mybatisPath);
        //创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //通过SqlSessionFactoryBuilder对象的build方法创建SqlSessionFactory对象
        SqlSessionFactory factory = sqlSessionFactoryBuilder.build(is);
        //通过工厂类的openSession方法获取sql执行对象
        SqlSession sqlSession = factory.openSession();
        //sql执行对象的selectOne方法
        //获取第一个参数,即执行id:由namespace + . + SQL语句标签id
        String id = "com.ling.mybatis.dao.UserDao" + "." + "findUserById";
        User user = sqlSession.selectOne(id);
        System.out.println(user);
        //关闭sqlSession
        sqlSession.close();
    }

基础步骤

第一步:设置中心配置文件的路径

第二步:使用Resources静态方法,将中心配置文件加载进字节输入流

第三步:获取SqlSessionFactoryBuilder对象,该对象的主要任务是创建factory对象

第四步:使用SqlSessionFactoryBuilder对象的build方法,传入字节输入流,解析中心配置文件,初始化数据库连接池,并且获取各个dao配置文件。

第五步:通过SqlSessionFactory对象的openSession方法获取sqlSession执行对象,该对象主要用于sql语句的执行操作。

第六步:定义字符串,锁定需要执行的语句

第七步:执行sql语句

SqlSessionFactory接口

接口作用

        SqlSessionFactory接口是sqlSession的工厂接口,主要作用是创建SqlSession对象

        SqlSessionFactory功能众多,创建过程较之其他比较缓慢,需要更多的时间和空间,在项目中有一个即可。

接口方法

openSession();获取一个默认的SqlSession对象,默认是需要手动提交事务的

openSession(boolean):boolean参数表示是否自动提交事务

        true:创建一个自动提交事务的SqlSession

        false:等同于没有参数的openSession

SqlSession接口

接口作用

        提供了大量的执行sql语句的方法,线程不安全

        针对线程不安全,需要注意使用步骤

使用步骤

1.在方法内部执行sql语句之前,先获取sqlSession对象

2.调用sqlSession方法对象,执行sql语句

3.关闭sqlSession,执行sqlSession的close方法

        如此一来,该sqlSession就只在方法内存在,在该方法所在执行的线程空间内存在,这样其他线程就无法获取这条线程内的数据对象。

接口方法

selectOne(String,Object):执行返回值只有一行的执行结果,多余一行会执行错误

selectMap(String,Object):执行返回一个map类型的接口

selectList(String,Object):执行返回一个list集合数据

insert(String,Object):执行添加操作

update(String,Object):执行修改操作

delete(String,Object):执行删除操作

commit:执行事务提交操作

rollback:执行事务回滚操作

MybatisUtils工具类

        由上文实现步骤我们可以看出,每一次进行数据库操作我们都需要进行以上七步的操作,但是七步操作中有大量的代码冗余,一到五步代码基本大致相同,因此我们可以写构造一个MybatisUtils工具类,专门用于mybatis初始化操作。

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory = null;

    //通过静态代码块,当类进行加载时赋值
    static {
        String sqlPath = "mybatisConfig.xml";
        try {
            //根据核心配置文件路径获取字节输入流
            InputStream resource = Resources.getResourceAsStream(sqlPath);
            //使用Builder对象的build方法获取factory对象
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //获取SqlSession对象(不自动提交事务)
    public static SqlSession getSqlSession(){
        //openSession方法中没有参数,则取消自动提交。传入true则打开自动提交
        return sqlSessionFactory.openSession();
    }
}

        此时我们简化了前五步步骤,但是第六步简单的字符串拼接和第七步方法的执行还是没有简化,而且我们在使用的过程中发现,接口好像根本没啥作用,接口的方法没有被调用,接口也没有实现类,接口好像白写了?

实现dao接口

        按照Javaweb学习阶段三层架构的代码书写习观我们创建impl文件夹,并且于文件夹内部创建dao接口实现类。

public class UserDaoImpl implements UserDao {
    @Override
    public List<User> findAllUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        String sqlPath = "com.ling.mybatis.dao.UserDao.findAllUser";
        List<User> list = sqlSession.selectList(sqlPath);
        sqlSession.close();
        return list;
    }
}

        我们将第六步第七步的操作步骤放到了接口实现类中,这样就完成了整合,当我们需要调用方法进行sql语句操作时,创建dao接口实现类对象,执行其对应的方法即可。

        但是对于以上整合方案并不能帮助我们简化程序书写的步骤,只是简单的对数据操作进行了整合操作,我们需要一种可以直接完成数据操作的方法

使用代理模式

mybatis的dao代理

代码书写

getMapper(dao接口的class类)

@Test
    public void test2() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        userDao.findUserById(1);
        sqlSession.close();
    }

        通过sqlSession的getMapper方法获取代理对象,我们在学习Spring框架的Aop增强时学习过了proxy代理模式,主要工作原理是通过反射机制创建目标增强对象的子类,并且在不改变原方法内容的情况下强化方法的参数,内容,返回值。

        这里的getMapper方法就是使用代理模式,创建userDao的实现类对象,并且通过类加载器和反射机制获取UserDao的路径名,以及方法名,自动的完成拼接,并且选择合适的sqlSession方法执行增删改查的操作。这里就回收了为什么我们在设置dao层配置文件namespace属性尽量要设置为dao接口src下全路径,为什么sql语句标签id要设置为方法名。

理解参数

通过Java程序把数据传入到mapper文件中的sql语句,这里的参数主要是指dao接口方法中的形参

parameterType

        表示参数类型,指定dao方法的形参数据类型。这个形参的数据类型是给mybatis使用。mybatis在给sql语句的参数赋值时使用,我们在jdbc中学习过的防止sql语句注入,使用preparedStatement对象。我们对?内容进行属性值注入时,需要使用对应的setXXX(索引,值)方法进行输入,这里的parameterType就是在选择注入的属性类型。

<select id="findUserById" parameterType="java.lang.Integer" resultType="com.ling.mybatis.pojo.User">
        select * from user where id = #{id}
</select>

        mybatis可以使用反射机制获取dao接口方法参数类型,因此parameterType可以省略不写

传递一个简单类型参数

简单类型:Java中的基础数据类型

        当传递的参数时一个简单类型的参数时,mapper文件使用#{任意字符}获取这个参数值

<select id="findUserById"  resultType="com.ling.mybatis.pojo.User">
     select * from user where id = #{id}
</select>

传递多个简单类型参数

        使用@Param注解,用于命名参数,在方法的形参前面使用,定义参数名。这个名称要用于mapper文件中,也就是#{}内的值就是参数命名后的名称

    List<User> findUserByIdOrUsername(@Param("Sid") Integer id, @Param("Susername") String username);
    <select id="findUserByIdOrUsername" resultType="com.ling.mybatis.pojo.User">
        select * from user where id = #{Sid} or username = #{Susername}
    </select>

使用实体类属性传递参数

        方法参数直接传入一个实体类,那么mybatis就会自动解析实体类属性,并且根据属性名称查找配置文件中#{}内的参数名称,如果匹配,那么就赋值。

int insertUser(User user);
    <insert id="insertUser">
        insert into user values(#{id},#{username},#{password})
    </insert>

按照位置传递参数

        按照位置传参,接口中的多个参数就不需要添加@Param注解起别名,只需要在sql语句中使用#{arg索引}就可以指定传入第几个参数

List<User> findUserByIdOrUsername(Integer id, String username);
    <select id="findUserByIdOrUsername" resultType="com.ling.mybatis.pojo.User">
        select * from user where id = #{arg0} or username = #{arg1}
    </select>

使用map传参

        map中的key值就对应了#{}中的名称,value值即为注入的值。

List<User> findUserByIdOrUsername(Map map);
<select id="findUserByIdOrUsername" resultType="com.ling.mybatis.pojo.User">
        select * from user where id = #{id} or username = #{username}
    </select>

#占位符与$占位符的区别

        #占位符实际上是PrepareStatement编译了sql语句之后对于值的一个注入,而$占位符做的是简单的字符串拼接,也就是使用普通的Statement。

$特点:

        1.使用的是Statement对象,执行SQL语句时效率低

        2.${}占位符,使用的是字符串拼接的方式,有sql注入的风险,有代码安全性问题

        3.${}数据是原样使用的,不会区分数据类型

        4.${}常常用作表名或者列名,在能保证数据安全的情况下使用${}

#特点:

        1.使用PrepareStatement对象,执行sql语句,效率高。

        2.使用PrepareStatement对象,能够避免sql语句注入问题,SQL语句执行更安全

        3.#{}常常作为列值使用,位于等号的右侧,#{}位置的值和数据类型有关

封装MyBatis输出结果

resultType

resultType属性:在执行select时使用,作为<select>标签的属性出现的

resultType:表示结果类型,mysql执行sql语句,得到java对象出现的类型,他的值有两种

        1.java类型的全限定名称(我们之前一直使用的)

        2.在中心配置文件中设置的别名

        别名我在第一篇文章中讲解中心配置文件的时候详细说过,他是在中心配置文件的typeAliases标签内部设置的,如果使用package标签取别名,那么就是整包一起取,如果使用typeAlias标签的话就是一个一个取,具体的优缺点可以看我的第一篇文章

中心配置文件:

<typeAliases>
    <!--路径名之间用/隔开或者用.隔开都行-->
    <!--给一个包下所有类取别名,别名就是类名,不用区分大小写-->
    <package name="com.ling.mybatis.pojo"/>
    <!--给一个单独的类起任意别名-->
    <typeAlias type="com.ling.mybatis.pojo.User" alias="user"></typeAlias>
</typeAliases>

dao层配置文件:

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

当查询结果为自定义类型时

        其实就是我们一直写的以User作为返回值结果,这就是将查询的结果封装到类对象中。

        当sql语句查询到数据后,mybatis会根据resultType会根据配置内容使用java反射调用无参构造器创建对象,然后将获取到的结果集对应的key值与对象属性值进行比对,如果属性名称相同就把值注入到对象中。如果查询到多行数据,那么就会创建多个对象,并且将对象存放入list集合中。

User findUserById(Integer id);
    <select id="findUserById" resultType="user">
        select * from user where id = #{id}
    </select>

当查询的结果为简单类型时

        设置resultType直接设置为java中的路径

    <select id="getSum" resultType="java.lang.Integer">
        select count(*) from user
    </select>
Integer getSum();

当查询结果为Map类型时

        mybatis会将sql语句查询结果以键值对的形式添加到map集合中,但是如果使用map作为返回值,那么该程序执行结果只能有一行查询结果,多了就会报错

    <select id="getMapper" resultType="java.util.Map">
        select * from user where id = #{id}
    </select>
Map<Object,Object> getMapper(Integer id);

resultMap自定义查找结果

使用resultMap可以自定义结果集中属性与对象属性的对应关系,常用于对象属性与查询结果列名不相同的情况。

如何使用:

1.主键名使用id标签,column指定结果集中的列名,property指定类中的属性名。

2.其他列名使用result标签,column指定结果集中的列名,property指定类中的属性名。

3.id属性用于设置该结果集的名称

4.type属性用于指定需要匹配的类

5.select标签中resultMap属性设置为resultMap标签中的id值

List<UserDocument> findAllUserDocument();
    <resultMap id="userDocument" type="com.ling.mybatis.pojo.UserDocument">
        <!--设置列名与类属性的对应关系-->
        <!--主键名使用id标签一一对应-->
        <id column="id" property="userId"></id>
        <!--其他属性使用result标签一一对应-->
        <result column="age" property="userAge"></result>
        <result column="game" property="userGame"></result>
    </resultMap>

    <select id="findAllUserDocument" resultMap="userDocument">
        select * from userdocument
    </select>

        select标签属性resultMap获取了配置相关信息的resultMap标签唯一名称,通过唯一名称查找到了配置好的resultMap,根据type属性获取返回值类型,并且解析id标签与result标签内容,获取属性值对应关系,最后将查找到的值首先按照对应关系赋值,然后正常赋值。

有关like查询

当查询语句需要使用like

例如:select * from user where name like %zhang%;

第一种:将%zhang%整体作为一个字符串传入

List<User> findUserLike1(String username);
    <select id="findUserLike1" resultType="com.ling.mybatis.pojo.User">
        select * from user where username like #{username}
    </select>
@Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> list = userDao.findUserLike1("%z%");
        for (User user : list) {
            System.out.println(user);
        }
        sqlSession.close();
    }

第二种:在sql语句中按照标准书写,"%" 值 "%" 值...  其中%与值中间必须有空格

List<User> findUserLike2(String username);
    <select id="findUserLike2" resultType="com.ling.mybatis.pojo.User">
        select * from user where username like "%" #{username} "%"
    </select>
@Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> list = userDao.findUserLike1("z");
        for (User user : list) {
            System.out.println(user);
        }
        sqlSession.close();
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Aristocrat l

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值