mybatis基础知识

mybatis基础知识

对原生态jdbc程序中问题总结

1.1jdbc程序

使用jdbc查询mysql数据库中用户表的记录

1.2JDBC开发

定义

Connection–>PreparedStatement–>ResultSet

加载数据库驱动–>通过驱动管理类获取数据库链接–>定义sql语句?表示占位符---->获取预处理statement–>设置参数,依次设置占位符表示的值–>向数据库发出sql执行查询,查询出结果集–>遍历查询结果集–>释放资源,按照申请资源的 顺序

1.2问题总结

  1. 数据库连接,使用时就连接,不使用时就释放,对数据库频繁的连接开启和关闭,造成数据库资源的浪费,影响数据库的性能。

    解决方案:数据库连接池

  2. 讲sql语句硬编码到Java代码中,若sql语句修改,需要重新编译java代码,不利于系统维护

    解决方案:将sql语句配置到xml配置文件中

  3. 向prepareStatement设置参数的时候,对占位符位置和设置参数值,硬编码在java代码中

    设想:将sql语句和占位符号以及参数全部配置在xml文件中

  4. 从resutSet中遍结果集数据时,存在硬编码,将获取表的字段进行硬编码,不利于系统维护

    设想:将查询的结果集,自动映射成java对象。

MyBatis框架

2.1MyBatis是什么?

MyBatis是一个持久层框架,是apache下的顶级项目

Mybatis让程序员主要精力放在sql上,通过MyBatis提供的映射方式,自由灵活的生成(半自动化,大部分需要程序员编写sql)满足需要的sql语句

MyBatis可以将向prepareStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射)

2.2MyBatis框架开发步骤以及结构

1.SqlMapConfig.xml(是mybatis的配置文件,名称自定)

配置了数据源,事务等mybatis运行环境

配置了映射文件(配置sql语句)

mapper.xml(映射文件)、mapper.xml、mapper.xml

2.SqlFactionFactory(会话工厂)

作用:创建SqlSession

3.SqlSession(会话),是一个接口,面向用户(程序员)的接口

作用:操作数据库(发出sql增删改查)

4.Executor(执行器),是一个接口(基本执行器、缓存执行器)

作用:SqlSession内部通过执行器操作数据库

mapped statement(底层封装对象)

作用:对操作数据库存储封装。包括sql语句,输入参数、输出结果类型

输入参数类型

java简单类型,hashmap,pojo自定义

输出结果类型

java简单类型,hashmap,pojo自定义

入门程序

3.1需求以及环境

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

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

添加用户

删除用户

=================================================

Mybatis的jar包,一个包

Mybatis 的操作指南

mysql的驱动包

3.2log4j.properties

classpath下新建文件

步骤 1:添加 Log4J 的 jar 包

因为我们使用的是 Log4J,就要确保它的 jar 包在应用中是可用的。要启用 Log4J,只要将 jar 包添加到应用的类路径中即可。Log4J 的 jar 包可以在上面的链接中下载。

对于 web 应用或企业级应用,则需要将 log4j.jar 添加到 WEB-INF/lib 目录下;对于独立应用,可以将它添加到JVM 的 -classpath 启动参数中。

步骤 2:配置 Log4J

配置 Log4J 比较简单,假如你需要记录这个映射器接口的日志:

package org.mybatis.example;
public interface BlogMapper {
  @Select("SELECT * FROM blog WHERE id = #{id}")
  Blog selectBlog(int id);
}

在应用的类路径中创建一个名称为 log4j.properties 的文件,文件的具体内容如下:

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

添加以上配置后,Log4J 就会记录 org.mybatis.example.BlogMapper 的详细执行操作,且仅记录应用中其它类的错误信息(若有)。

你也可以将日志的记录方式从接口级别切换到语句级别,从而实现更细粒度的控制。如下配置只对 selectBlog 语句记录日志:

log4j.logger.org.mybatis.example.BlogMapper.selectBlog=TRACE

与此相对,可以对一组映射器接口记录日志,只要对映射器接口所在的包开启日志功能即可:

log4j.logger.org.mybatis.example=TRACE

某些查询可能会返回庞大的结果集,此时只想记录其执行的 SQL 语句而不想记录结果该怎么办?为此,Mybatis 中 SQL 语句的日志级别被设为DEBUG(JDK 日志设为 FINE),结果的日志级别为 TRACE(JDK 日志设为 FINER)。所以,只要将日志级别调整为 DEBUG 即可达到目的:

log4j.logger.org.mybatis.example=DEBUG

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

3.5.1创建po类(输出的参数类型,类的形式)

字段名和属性名对应(model类)

3.5.2映射文件(User.xml)

映射文件命名:

User.xml(原始ibatis命名),mapper代理开发映射文件名称叫XXXMapper.xm

比如说UserMapper.xml、ItemsMapper.xml

  1. parameterType:指定输入参数的类型,这里指定int

  2. #{}表示一个占位符号
    #{id}:其中的id表示接收输入的参数,参数名称是id,如果输入参数是简单类型,#{}中的参数名可以任意,可以value或其他名称

    ${}表示拼接字符串,将接收的内容不加任何修饰拼接在sql中,不建议使用?‍

  3. resultType:指定sql输出结果所映射的Java对象

在映射文件中配置sql语句
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
<!--    在映射文件中配置很多sql语句-->
<!--    通过id查询用户id-->
<!--    通过select执行数据库查询
        id:标识映射文件的sql,称为statement的id
        将sql语句封装到mappedStatement对象中,所以将id称为statement的id-->
<!--    parameterType:指定输入参数的类型,这里指定int-->
<!--    #{}表示一个占位符号
        #{id}:其中的id表示接收输入的参数,参数名称是id,
        如果输入参数是简单类型,#{}中的参数名可以任意,可以value或其他名称
        resultType:指定sql输出结果所映射的Java对象-->
    <select id="findUserById" parameterType="int" resultType="arraylist">
        SELECT * FROM test WHERE id=#{id}
    </select>
</mapper>

============================================================

附:mapper的namespace属性

============================================================

在mybatis中,映射文件中的namespace是用于绑定Dao接口的,即面向接口编程。

**当你的namespace绑定接口后,你可以不用写接口实现类,mybatis会通过该绑定自动帮你找到对应要执行的SQL语句,**如下:

假设定义了IArticeDAO接口

public interface IArticleDAO
{
   List<Article> selectAllArticle();
}

对于映射文件如下:

<mapper namespace="IArticleDAO">
    <select id="selectAllArticle" resultType="article">
            SELECT t.* FROM T_article t WHERE t.flag = '1' ORDER BY t.createtime DESC
     </select>

请注意接口中的方法与映射文件中的SQL语句的ID一一对应 。
则在代码中可以直接使用IArticeDAO面向接口编程而不需要再编写实现类。

=============================================================

3.5.3在SqlMapConfig.xml加载映射文件

<mappers>
    <mapper resource="sqlmap/User.xml"/>
</mappers>

=============================================================

附:关于Maven项目中无法加载MyBatis映射文件解决办法

=============================================================

还有另外一种解决方法,就是将映射文件放在resources/sqlmapping文件夹下,然后在mybatis-config.xml中进行如下导入:(需要设置resource文件夹)

 <mappers>
   <mapper resource="sqlmapping/UserMapper.xml"/>
 </mappers>

=============================================================

3.5.4程序的编写

创建会话工厂,利用会话工厂获得SqlSession,利用SqlSession执行

  1. selectone表示查询出一条记录的映射
  2. selectList表示查询List对象(多条结果)
  3. sqlSession.selectOne(“MybatisTest.getName”, 12);中第一个参数:映射文件中statement的id,等于=namespace+“0”+statement的id, 第二个参数: 指定和映射文件中所匹配的parameterType类型的参数(输入参数)

===========================================

SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);

===========================================

**创建会话工厂:**加载配置文件,得到文件流,传入会话工厂的build方法

=======================================================

//mybatis配置文件
String resource = “mybatis_config.xml”;
//得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);

=======================================================

@Test
    public void find() throws IOException {

        //mybatis配置文件
        String resource = "mybatis_config.xml";
        //得到配置文件流
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //创建会话工厂,传入mybatis文件的配置信息
        SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);

        //通过工厂获得SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //通过SqlSession操作数据库
        /**
         * 第一个参数:映射文件中statement的id,等于=namespace+"0"+statement的id
         * 第二个参数: 指定和映射文件中所匹配的parameterType类型的参数(输入参数)
         */
        Userid userid=sqlSession.selectOne("MybatisTest.getName", 12);
        System.out.println(userid);
        //释放资源,最好使用try-catch 的finally语句
    }
  1. **#{}表示一个占位符,**可以是简单类型,pojo,hashmap
  2. **${}表示拼接字符串,将接收的内容不加任何修饰拼接在sql中。**如果传入参数为简单类型,括号内只能写value

使用${}会有安全隐患,如sql注入

mybatis开发dao

SqlSession使用范围

4.1.1 SqlSessionFactoryBuilder

通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory

将SqlSessionFactory当作工具类即可,不需要使用单例管理SqlSessionFactoryBuilder

4.1.2 SqlSessionFactory

通过SqlSessionFactory创建SqlSession,使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例)

将来mybatis和spring整合后,使用单例模式管理sqlSessionFactory

4.1.3 SqlSession

SqlSession是一个面向用户(程序员)的接口

SqlSession中提供了很多操作数据库的方法:如:selectOne,selectList

SqlSession线程不安全,在SqlSession实现类中除了有实现接口中的方法(操作数据库)还有数据域属性。

SqlSession最佳应用场合在方法体内,定义局部变量使用。

4.2 原始dao开发方法(程序员需要写dao接口和dao实现类)

4.2.1 思路

程序员需要写dao接口和dao实现类

向dao中注入SqlSessionFactory,在方法体内通过SqlSessionFactory创建SqlSession

4.2.2 内容

编写dao

public interface MyBatisTest {
    List<Object> getName(Integer id);

    void insertUser();

    void deleteUser();

    void updateId();
}

编写实现类

public class TestDao implements MyBatisTest{
    public SqlSessionFactory sqlSessionFactory;

    public TestDao(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    @Override
    public List<Object> getName(Integer id) {
        SqlSession sqlSession=sqlSessionFactory.openSession();
        List<Object> userids=sqlSession.selectOne("MybatisTest.getName",id);
//      释放资源
        sqlSession.close();
        return userids;
    }

    @Override
    public void insertUser() {

    }

    @Override
    public void deleteUser() {

    }

    @Override
    public void updateId() {

    }
}

4.3 mapper代理的方法(程序员只需要mapper接口(相当于dao接口))

4.3.1思路

程序员需要开发mapper接口

程序员还要编写mapper.xml文件

程序员只需要编写mapper接口(相当于dao接口)

mybatis自动生成mapper接口实现类代理对象

4.3.2开发规范:

现有默认开发模式就是mapper

  1. mapper对应的id是类
  2. 语句对应的id是方法名
  3. mapper方法的输入类型和mapper.xml中statement的paramentType指定的类型一样
  4. mapper方法的返回类型和mapper.xml中statement的resultType指定的类型一样

自动注入Session工厂类,定义UserMapper(dao)类,使用sqlSession获取mapper类

SqlSession sqlSession = sqlSessionFactory.openSession();

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

MyBatis增删改查

=============================================

注意!!!sql语句不需要写分号

==============================================

查询

映射文件

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
<!--    在映射文件中配置很多sql语句-->
<!--    通过id查询用户id-->
<!--    通过select执行数据库查询
        id:标识映射文件的sql,称为statement的id
        将sql语句封装到mappedStatement对象中,所以将id称为statement的id-->
<!--    parameterType:指定输入参数的类型,这里指定int-->
<!--    #{}表示一个占位符号
        #{id}:其中的id表示接收输入的参数,参数名称是id,
        如果输入参数是简单类型,#{}中的参数名可以任意,可以value或其他名称
        resultType:指定sql输出结果所映射的Java对象-->
    <select id="findUserById" parameterType="int" resultType="arraylist">
        SELECT * FROM test WHERE id=#{id}
    </select>
</mapper>

selectOne

返回一个结果

selectList

返回结果集

=============================================================

添加

映射文件

<!--    添加用户,
        parameterType:指定输入参数类型是pojo(包括用户信息)
        #{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL来获取对象的属性值
        -->
    <insert id="insertUser" parameterType="model.Userid">
        INSERT INTO test(id, name) value (#{id},#{name})
    </insert><!--    添加用户,
        parameterType:指定输入参数类型是pojo(包括用户信息)-->
    <insert id="insertUser" parameterType="model.Userid">
        INSERT INTO test(id, name) value (#{id},#{name});
    </insert>

获取sqlSession后需要提交事务:sqlSession.commit();整合spring后不需要

insert

自增的不需要加入sql语句

若想返回刚刚插入记录的自增主键:

SelectKey标签

自增主键
<!--    添加用户,
        parameterType:指定输入参数类型是pojo(包括用户信息)
        #{}中指定pojo的属性名,接收到pojo对象的属性值,mybatis通过OGNL来获取对象的属性值
        SELECT LAST_INSERT_ID():得到刚刚insert进去的主键值,只适用自增主键
        keyProperty:将查询到的主键设置到parameterType指定的对象的哪个属性
        order:SELECT LAST_INSERT_ID()执行顺序,相对于insert语句来说它的执行顺序

        -->
    <insert id="insertUser" parameterType="model.Userid">
        INSERT INTO test(id, name) value (#{id},#{name})
        <selectKey keyProperty="id" order="AFTER" resultType="Intenger">
            SELECT LAST_INSERT_ID()
        </selectKey>
    </insert>
非自增主键

使用uuid()替换

删除

映射文件

<delete id="deleteUser" parameterType="integer">
        DELETE FROM test WHERE id =#{id}
    </delete>

delete方法

更新

映射文件

<update id="updateId" parameterType="model.Userid">
        UPDATE test SET name=#{name} WHERE id=#{id}
    </update>

update方法

输入映射

通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型

6.1 传递pojo的包装对象

6.1.1 需求

完成用户信息的综合查询,需要传入查询条件很复杂(可能包括用户信息、其他信息,比如商品、订单)

6.1.2 定义包装类型pojo

针对上面的条件,建议使用自定义包装的pojo

在包装类型的pojo中将复杂的查询条件包装进去。

在po包中创建Vo

vo po pojo

6.1.3 利用包装类型

视图层model UserVo

编写视图层的vo时可以直接在构建类,类中定义一个或几个基础对象

package model;

public class UserIdQueryVo {
    /**
     * 在这里写额外的信息,如订单等等
     */

    /**
     * 用户的基础信息
     */
    private Userid userid;

    public Userid getUserid() {
        return userid;
    }

    public void setUserid(Userid userid) {
        this.userid = userid;
    }
}

6.1.3映射文件(mapper.xml)

在UserMapper.xml中定义用户信息综合查询(查询条件复杂,通过高级查询进行复杂关联查询).

7. 输出映射

7.1 resultType

使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。

如果查询出来的列名和pojo中的属性名全不一致,没有创建pojo对象。

只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。

7.1.1 .1 需求

用户信息的综合查询列表总数,通过查询总数和上边的用户综合查询列表才可实现分页。

7.1.1.2 实现

 <select id="findUserCount" parameterType="model.UserIdQueryVo" resultType="int">
        SELECT COUNT(*) FROM test WHERE test.name= #{id}
    </select>

7.1.1.3 总结

查询出来的结果集只有一行或一列,可以使用简单类型进行输出映射

7.1.2 输出pojo对象和pojo列表

不管输出pojo单个对象还是 一个列表(list中包括pojo),在mapper.xml中resultType指定的类型是一样的。

在mapper.java指定的方法返回值类型不一样

  1. 输出单个pojo对象,方法返回值是单个对象类型
  2. 输出多个pojo对象,方法返回值是List对象List

动态的代理对象中是根据mapper方法的返回值类型确定调用selectOne还是SelectList

7.2 resultMap

mybatis中使用resultMap完成高级输出结果映射。

7.2.1 resultMap的用法

如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系

  1. 定义resultMap
  2. 使用resultMap作为statement的输出映射类型

7.2.2 将下面的sql使用User完成映射

SELECT id id_ ,username username_ FROM WHERE id=#{value}

user类中属性名和上面查询列名不一致

<!--将SELECT id id_ ,username username_ FROM WHERE id=#{value} 和User类中的属性做一个映射关系
    type:resultMap最终映射的java类型,可以使用别名
    id:对resultMap的唯一标识
-->
    <resultMap id="userResultMap" type="model.Userid">
<!--        id表示查询结果集中的唯一标识
           column标识查询出的列名
           property:type指定的pojo类型中的属性名-->
<!--       最终resultMap对Column和property作映射关系-->
        <id column="id_" property="id"/>
<!--        对普通列的定义-->
<!--        result:对普通映射名的定义-->
<!--        column:查询出来的列名-->
<!--        property:type指定的pojo类型的属性名-->
<!--        最终resultMap对Column和property作映射关系
			如果这个resultMap在其他的mapper文件,前面需要加namespace
-->
        <result column="name_" property="name"/>
    </resultMap>
<select id="findUserCount" parameterType="model.UserIdQueryVo" resultMap="userResultMap">
            SELECT COUNT(*) FROM test WHERE test.name= #{id}
</select>

mybatis支持的别名

别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
map Map
posted @ 2019-10-28 17:13  jirath  阅读(229)  评论(0编辑  收藏  举报