mybaits入门到精通

正文

一,MyBatis的执行流程

    mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的
    信息。
    mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂。
    通过SqlSessionFactory,可以创建SqlSession即会话。Mybatis是通过SqlSession来操作数据库的。
    SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
    Executor执行器要处理的SQL信息是封装到一个底层对象MappedStatement中。该对象包括:SQL语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括java的简单类型、HashMap集合对象、POJO对象类型。
--------------------- 

第一章. Mybatis 入门

Mybatis是一款优秀的支持自定义SQL查询、存储过程和高级映射的持久化框架,消除了几乎所有的jdbc代码和参数的手动设置以及结果集的检索。

Mybatis可以使用XML或注解进行配置和映射,Mybatis通过将参数映射到配置的SQL形成最终执行的SQL语句,最后将执行SQL结果映射成Java对象返回。

与其他的ORM(对象关系映射)框架不同,Mybatis并没有将Java对象与数据库表关联起来,而是将Java方法与SQL语句关联。

Mybatis允许用户充分利用数据库的各种功能,例如存储过程,视图,各种复杂的查询以及某数据库的专有特性。

如果要对遗留数据库、不规范的数据库进行操作,或者要完全控制SQL的执行,Mybatis将会是一个不错的选择。

Mybatis提供了一个映射引擎,声明式的将SQL语句的执行结果与对象树映射起来。通过使用一种内建的类xml表达式语言,SQL语句可以被动态生成。

Mybatis提供了默认情况下基于Java Hashmap的缓存实现,以及与OScache、Ehcache、Hazelcast和Memcached连接的默认连接器,同时还提供了API供其他缓存实现使用。 

第二章. Mybatis XML方式的基本用法

由于Java中的基本数据类型会有默认值,在动态SQL中和null进行比较时结果总为true,所以在实体类中不要使用基本数据类型。
	
导包(核心,依赖包,数据库驱动包)
有表,有domain
核心配置文件 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">
  <configuration>
    <!--
         每个环境都代表对应一个数据库连接
         environments:环境(们)
    -->
   <!--引入 db.properties文件-->
   <properties resource="db.properties" />
    <environments default="development">
         <!-- 真实数据库环境【用户】 -->
         <environment id="development">
           <transactionManager type="JDBC" />
           <!--dataSource:数据源(连接池) -->
           <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>
    <!-- 读取SQL的映射文件 -->
       <mapper resource="cn/itsource/domain/ProductMapper.xml" />
      </mappers>
    创建映射文件 XxxMapper.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:命名空间(一个domain对应一个这个xml)
        -->
  <mapper namespace="cn.itsource.domain.ProductMapper">
<!--
    如果到时候想找到这条SQL: namespace+id
        等会要找到它:cn.itsource.domain.ProductMapper.findOne
        parameterType:代表传参类型
            long -> Long  _long -> long
        resultType:返回的某一个条数的类型(必需写全限定名)
 -->
       <select id="findOne" parameterType="long" resultType="cn.itsource.domain.Product" >
               select * from product where id = #{id}
      </select>
  </mapper>

以前使用SqlSession通过命名空间调用Mybatis方式时,首先需要用到命名空间和方法id组成的字符串来调用相应的方法。当参数多余1个的时候,需要将所有参数放到一个Map对象中。通过Map传递多个参数,使用起来很不方便,而且还无法避免很多重复的代码。使用接口调用方法就会方便很多,Mybatis使用Java的动态代理可以直接通过接口来调用相应的方法,不需要提供接口的实现类,更不需要在接口类中使用SqlSession以通过命名空间间接调用。另外,当有多个参数的时候,通过参数注解@Param设置参数的名字省去了手动构造Map参数的过程,尤其在Spring中使用的时候,可以配置为自动扫描所有的接口类,直接将接口注入到需要用到的地方。

接口可以配合xml方式使用,也可以配合注解方式来使用。xml方式可以单独使用,但是注解方式必须在接口中使用。

映射XML和接口的命名需要符合如下规则:

1. 当只使用XML而不使用接口的时候,namespace值可以设置为任意不重复的名称。

2. 标签的id属性值在任何时候都不能出现英文".",并且同一个命名空间下不能出现重复的id。

3. 因为接口方法是可以重载的,所以接口中可以出现多个同名但参数不同的方法,但是XML中id的值不能重复,因而接口中的所有同名方法会对应着XML中的同一个id的方法。最常见的用法就是,同名方法中其中一个方法增加一个RowBound类型的参数用于实现分页查询。

2.1. 标签用法

    constructor:通过构造方法注入属性的结果值。构造方法中的idArg、arg参数分别对应着id、result标签,它们的含义相同,只是注入方式不同。

    resultMap中的id和result标签包含的属性相同。不同的地方在于。id代表的是主键(或唯一值)的字段(可以有多个),他们的属性值是通过setter方法注入的。

    property:映射到列结果的属性。可以映射简单的如“username”这样的属性,也可以映射一些复杂对象中的属性,例如“address.number”,这会通过“.”方式的属性嵌套赋值。

    javaType:一个Java类的完全限定名,或一个类型别名(通过TypeAlias配置或者默认的类型)。如果映射到一个JavaBean,Mybatis通常可以自动判断属性的类型。如果映射到HashMap,则需要明确的指定javaType的类型(即resultMap的Type属性值设定)。

    jdbcType:列对应的数据库类型。JDBC类型仅仅需要对插入,更新,删除操作可能为空的列进行处理。这是JDBC jdbcType的需要,而不是Mybatis的需要。

    typeHandler:使用这个属性可以覆盖默认的类型处理器。这个属性值是类的完全限定名或类型别名。

接口中定义的返回值类型必须和XML中配置的resultType类型(或resultMap中的Type)一致,否则就会因为类型不一致而抛出异常。

当返回值最多只有1个结果的时候(可以0个),可以将接口返回值定义为T,而不是List<T>,当然,如果将返回值改为List<T>或T[],也没有问题,只是不建议这么做。刚执行的SQL返回多个结果时,必须使用List<T>或T[]作为返回值,如果使用T,就会抛出TooManyResultsException异常。

可以通过在resultMap中配置property属性和column列的映射,或者在SQL中设置别名这两种方式实现将查询列映射到对象属性的目的。

property属性或别名要和对象中属性的名字相同,但是实际匹配时,Mybatis会先将两者都转为大写形式,然后再判断是否相同。即property=“username”和property=“userName”都可以匹配到对象的userName属性上。判断是否相同的时候要使用USERNAME,因此在设置property属性或别名的时候,不需要考虑大小写是否一致。但是为了便于阅读,要尽可能按照统一的规则来设置。

在数据库中,由于大多数数据库设置不区分大小写,因此下划线方式的命名很常见,如user_name, user_email。在Java中,一般都使用驼峰命名,如userName,userEmail。因为数据库和Java中的这两种命名方式很常见,因此Mybatis还提供了一个全局属性mapUnderscoreToCamelCase, 通过配置这个属性为true可以自动将以下划线方式命名的数据库列映射到Java对象的驼峰式命名属性中。

2.2. 标签用法

    parameterType:参数的完全限定类名或别名,属性可选,因为Mybatis可以推断出传入语句的具体参数,因此不建议配置此参数。

    flushCache:默认值为true,任何时候只要语句被调用,都会清空一级缓存和二级缓存

    timeout:设置在抛出异常前,驱动程序等待数据库返回请求结果的秒数。

    useGeneratedKeys:默认值为false。如果设置为true,Mybatis会使用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键。

    keyProperty:Mybatis通过getGeneratedKeys获取主键值后将要赋值的属性名。如果希望得到多个数据库自动生成的列,属性值也可以是以逗号分隔的属性名称列表。

    keyColumn:仅对INSERT和UPDATE有用。通过生成的键值设置表中的列名,这个设置仅在某些数据库(如PostgreSQL)中是必须的,当主键列不是表中的第一列时需要设置。如果需要得到多个生成的列,也可以是逗号分隔的属性名称列表。

为了防止类型错误,对于一些特殊的数据类型,建议指定具体的jdbcType值。例如headImg指定BLOB类型,createTime指定TIMESTAMP类型。

由于数据库区分date,time,datetime类型,但是Java中一般都使用java.util.Date类型。因此为了保证数据类型的正确,需要手动指定日期类型。date,time,datetime对应的JDBC类型分别为DATE、TIME、TIMESTAMP。
javaType 	jdbcType 	数据库类型 	测试结果
Date 	Timestamp(不指定默认) 	datetime  	正确
Date 	DATE 	datetime  	正确
Date 	TIME 	datetime  	错误 

通过上面的测试,说明数据库的datetime类型可以存储DATE(时间部分默认为00:00:00)和TIMESTAMP这两种类型的时间,不能存储TIME类型的时间。将数据库的字段类型修改为time时,就可以正确映射过去了。

2.3. 使用JDBC方式返回主键自增的值

在使用主键自增(如MySQL、SQL Server数据库)时,插入数据库后可能需要得到自增的主键值,然后使用这个值进行一些其他的操作。

<insert id="insert2" useGeneratedKeys="true" keyProperty="id">
	insert into sys_user(
		user_name, user_password, user_email, 
		user_info, head_img, create_time)
	values(
		#{userName}, #{userPassword}, #{userEmail},
		#{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP})
</insert>

useGeneratedKeys设置为true后,Mybatis会使用JDBC的getGeneratedKeys方法来取出数据库内部生成的主键。获取主键值后将其赋值给keyProperty设置的属性。

当需要设置多个属性时,使用逗号隔开,这种情况下通常还需要设置keyColumn属性,按顺序指定数据库的列,这里列的值会和keyProperty配置的属性一一对应。

2.4. 使用selectKey方式返回主键自增的值

JDBC方式只适用于支持主键自增的数据库。有些数据库(如Oracle)不提供主键自增的功能,而是使用序列得到一个值,然后将这个值赋给id,再将数据插入数据库。对于这种情况,可以采用另外一种方式:使用<selectKey>标签来获取主键的值,这种方式不仅适用于不提供主键自增功能的数据库,也适用于提供主键自增功能的数据库。

<!--MySQL版本-->
<insert id="insert3">
	insert into sys_user(
		user_name, user_password, user_email, 
		user_info, head_img, create_time)
	values(
		#{userName}, #{userPassword}, #{userEmail}, 
		#{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP})
	<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
		SELECT LAST_INSERT_ID()
	</selectKey>
</insert>

keyColumn、keyProperty:和useGeneratedKeys的用法含义相同

resultType:设置返回值类型

order:和使用的数据库有关。在MySQL中,order设置为AFTER,因为主键值在insert执行成功后才能获取到。而在oracle中,order设置为BEFORE,因为oracle需要先从序列获取值,然后再将值作为主键插入数据库

<!-- Oracle 的例子,查询多个列的时候需要 keyColumn -->
<insert id="insertOracle">
	<selectKey keyColumn="id" resultType="long" keyProperty="id" order="BEFORE" databaseId="ORACLE">
		SELECT SEQ_USER.nextval from dual
	</selectKey>
	insert into sys_user(
		id, user_name, user_password, user_email, 
		user_info, head_img, create_time)
	values(
		#{id}, #{userName}, #{userPassword}, #{userEmail}, 
		#{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP})
</insert>

可以发现,selectKey元素放置的位置和之前的MySQL例子中的不同,其实这个元素放置的位置不会影响selectKey中的方法在insert前面或者后面执行的顺序,影响执行顺序的是order属性,这么写仅仅是为了符合实际的执行顺序,看起来更直观而已。

Oracle方式的insert语句中明确写出了id列和值#{id},因为执行selectKey中的语句后id就有值了,我们需要把这个序列值作为主键值插入到数据库中,所以必须指定id列,如果不指定这一列,数据库就会因为主键不能为空而抛出异常。

3.MyBatis的使用细节

1..添加时拿到返回的主键
     <!-- 
	parameterType:需要传入我们的对象
	useGeneratedKeys: 是否需要主键 
	keyColumn:主键所在的列,可以不用配置
	keyProperty:对象中的属性(代表主键的那个属性)
 -->
<insert id="save" parameterType="cn.itsource.domain.Product"
		useGeneratedKeys="true" 
		keyColumn="id"
		keyProperty="id"
	>
	insert into product (productName,dir_id,salePrice,supplier,brand,cutoff,costPrice)
		values (#{productName},#{dir_id},#{salePrice},#{supplier},#{brand},#{cutoff},#{costPrice})
</insert>
2.Log4j日志框架
      简介:Log4j有三个主要的组件:Loggers(记录器),Appenders (输出源)和Layouts(布局)。可简单理解为日志类别,日志要输出的地方和日志以何种形式输出。综合使用这三个组件可以轻松地记录信息的类型和级别,并可以在运     行时控制日志输出的样式和位置。
      使用步鄹:
                    1.导入日志需要得架包
                    2.在reource文件夹里面配置log4j.properties文件
                        ![resource文件结构](https://img-blog.csdnimg.cn/20190403184351368.png)
                        配置说明
                         log4j.properties(日志文件:)
                         log4j.rootLogger=ERROR, stdout
                         #log4j.rootLogger=NONE
                       log4j.logger.cn.itsource=TRACE   //把左边包名改成你自己的包名  TRACE:详细信息
                       log4j.appender.stdout=org.apache.log4j.ConsoleAppender
                      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 3.MyBatis中为一个类取别名
         
      内置别名(文档中有)
      自定义别名 mybatis-config.xml\
      别名不区别大小写
      注意它的配置顺序(如果配置错误会有提示)
      <!-- 配置别名 -->
        <typeAliases>
                <!-- 配置一个别名(不区分大小写) -->
               <!--<typeAlias type="cn.itsource.domain.Product" alias="product" />-->
      
             <!--这里是为整个包得类配置别名,他们得别名就是类名,不区分大小写-->
            <package name="cn.itsource.domain" />
        </typeAliases>
 4.列名与属性名不对应的解决方案resultMap
           
         添加与修改在相应位置修改名称即可
         查询需要创建一个resultMap
         使用的时候返回结果必需是resultMap

          <!--
               准备一个映射(ORM)配置
                resultMap:结果映射
           -->
          <resultMap id="productMapper" type="product">
                    <!--如果是主键不一致,使用id这个标签-->
                    <id column="id" property="id" />
                   <!--
                       result:某一个属性的映射
                       column:列名(表中) property:属性名(对象中)
                        -->
                       <result column="dir_id" property="dirId" />
             </resultMap>

     <!-- 查询所有数据 -->
         <select id="findAll" resultMap="productMapper" >
                      select * from product
        </select>

4.常见得几个面试题

    ①.mybatis相较于jdbc的优点?
           把sql语句从java代码中抽取出来,方便维护。并且修改sql时不用修改java代码
           不用手动设置参数和对结果集的处理。
    ②Hibernate与MyBatis的区别(重点)
       Hibernate是一个完整的ORM框架,功能更加强大,操作更加简单(性能不好控制),如果你要使用Hibernate控制性能
      做一个大项目,Hibernate确实不是很适合,如果大项目一定要使用Hibernate,进行混合使用,一般的操作使用Hibernate,对于性能要求比较高的使用原生的sql.
MyBatis不是完整的ORM框架,需要自己写SQL
好处:自己写SQL,自己控制性能(更好控制)
坏处:自己写SQL,很麻烦
    ③#与$的区别
         #支持传普通参数与对象(map),预编译的方案(性能更高,更加安全,没有SQL注入问题)
        $只支持传对象(map),就是一个拼接(性能不好,安全性不高)
        能用#都是#,实在不行了再用$

猜你喜欢

转载自blog.csdn.net/Secutiry_/article/details/88992827