Mybatis第一部分

Posted by Cfeng on April 10, 2019

学习视频来自黑马程序员,感谢!

对原生态jdbc程序问题总结

环境

java环境:jdk1.8 开发环境:IDEA 数据库 :mysql5.7

jdbc程序

  • 数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响 数据库性能。
    解决方法:使用数据库连接池管理数据库连接。

  • 将sql语句硬编码到java代码中,如果sql 语句修改,需要重新编译java代码,不利于系统维护。
    解决方法:将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。

  • 向preparedStatement中设置参数,对占位符号位置和设置参数值,硬编码在java代码中,不利于系统维护。
    解决方法:将sql语句及占位符和参数全部配置在xml中

  • 从result中遍历结果集数据时,存在硬编码,将获取表对字段进行硬编码,不利于系统维护。
    解决方法:将查询结果集,自动映射成java对象。

Mybatis框架原理

Mybatis是什么

  • 是一个持久层的框架,是apache下的顶级项目
  • 让程序员将主要精力放在sql。通过Mybatis提供的映射方式。半自动化生成满足需要sql。
  • 可以将向preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射出java对象。

Mybatis框架

  1. SqlMapConfig.xml(是Mybatis的全局配置文件)
    配置了数据项、事物等Mybatis运行环境
  2. 多个mapper.xml(配置映射关系、sql语句)
  3. SqlSessionFactory(会话工厂)根据配置文件创建工厂
    作用:创建SqlSession
  4. SqlSeesion(会话) 是一个接口,面向用户
    作用:操作数据库(发出sql增删改查)
  5. Executor(执行器),是一个接口(基本执行器、缓存执行器),
    作用:SqlSession内部通过执行器操作数据库
  6. mapped statement(底层分装对象)
    作用:对操作数据库存储封装,包括sql语句、输入、输出结果类型

Mybatis入门程序

需求:

  • 根据用户id(主键)查询用户信息
  • 根据用户名称模糊查询用户信息
  • 添加用户
  • 删除用户
  • 更新用户

创建SqlMapConfig.xml与映射文件User.xml

SqlMapConfig.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">
<configuration>
    <!-- 加载属性文件 -->
    <properties resource="db.properties">
        <!--properties中还可以配置一些属性名和属性值  -->
        <!-- <property name="jdbc.driver" value=""/> -->
    </properties>
    <typeAliases>
        <!-- 针对单个别名定义
        type:类型的路径
        alias:别名
        -->
        <!-- <typeAlias type="cn.itcast.mybatis.po.User" alias="user"/> -->
        <!-- 批量别名定义
        指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名(首字母大写或小写都可以)
        -->
        <package name="com.caoerzhe.pojo"/>
    </typeAliases>

    <!-- 和spring整合后 environments配置将废除-->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理,事务控制由mybatis-->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池,由mybatis管理-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="sqlmap/User.xml"/>
    </mappers>
</configuration>

User.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">
<!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离
注意:使用mapper代理方法开发,namespace有特殊重要的作用
-->
<mapper namespace="test">
</mapper>

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

public void findUserById() throws IOException {
    String resource = "SqlMapConfig.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //创建会话工厂,传入Mybaits文件配置信息
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //通过工厂得到SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 通过SqlSession操作数据库
    // 第一个参数:映射文件中statement的id,等于=namespace+"."+statement的id
    // 第二个参数:指定和映射文件中所匹配的parameterType类型的参数
    // sqlSession.selectOne结果 是与映射文件中所匹配的resultType类型的对象
    // selectOne查询出一条记录
    User user = sqlSession.selectOne("test.findUserById",1);
    System.out.println(user);
    sqlSession.close();
}

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

继续使用User.xml,添加根据用户名模糊查询用户信息的sql
根据用户名称模糊查询用户信息,可能返回多条 resultType:指定就是单条记录所映射的java对象类型
${}:表示拼接sql串,将接收到参数的内容不加任何修饰拼接在sql中。 使用${}拼接sql,引起 sql注入
${value}:接收输入 参数的内容,如果传入类型是简单类型,${}中只能使用value

<select id="findUserByName" parameterType="java.lang.String" resultType="com.caoerzhe.pojo.User">
    SELECT * FROM user WHERE username LIKE "%${value}%"
</select>

//查询多条记录
List<User> list = sqlSession.selectList("test.findUserByName","小");

添加用户

1.映射文件
在User.xml配置添加用户的statement

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

2.Java代码
没有spring整合前,要手动提交事物

User user = new User();
user.setUsername("小对的");
sqlSession.insert("test.insertUser",user);
//提交事物
sqlSession.commit();

3.如果设置自增主键,如何返回主键

User.xml

<insert id="insertUser" parameterType="com.caoerzhe.pojo.User">
    <!--
    将插入数据的主键返回,返回到user对象中

    SELECT LAST_INSERT_ID():得到刚insert进去记录的主键值,只适用与自增主键

    keyProperty:将查询到主键值设置到parameterType指定的对象的哪个属性
    order:SELECT LAST_INSERT_ID()执行顺序,相对于insert语句来说它的执行顺序
    resultType:指定SELECT LAST_INSERT_ID()的结果类型
    -->
    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
        SELECT LAST_INSERT_ID()
    </selectKey>
    insert into user (username,birthday,sex,address) value(#{username},#{birthday},#{sex},#{address})
</insert>

4.非自增主键的返回
使用mysql的uuid()函数生成主键,需要修改表中的id字段类型为string,长度设置成35位
执行思路:先通过uuid查询到主键,将主键设置到user对象中。
其次在insert执行时,从user对象中取出id属性值

<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
    SELECT uuid()
</selectKey>
insert into user(id,username,birthday,sex,address) value(#{id},#{username},#{birthday},#{sex},#{address})

删除用户与更新用户

User.xml

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

<!-- 根据id更新用户
分析:
需要传入用户的id
需要传入用户的更新信息
parameterType指定user对象,包括 id和更新信息,注意:id必须存在
#{id}:从输入 user对象中获取id属性值
-->
<update id="updateUser" parameterType="com.caoerzhe.pojo.User">
    update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>

Java代码

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

小结

  1. parameterType
    在映射文件中通过parameterType指定输入类型
  2. resultType
    在映射文件中通过resultType指定输出结果类型
  3. #{}与${}
    #{} 表示一个占位符 ,类型可以是简单类型,pojo,hashmap。 若果是简单类型,#{}中可以写成value或其他名称。 ${} 表示一个拼接符,会引起sql注入,不建议使用 ,也能简单,pojo,hashmap。 但是接受简单类型,只能用value
  4. selectOne和selectList
    selectOne 表示查询出一条记录进行映射 selectList 表示查询出一个列表进行映射