day-23 Mybatis

本文详细介绍了MyBatis框架的使用,包括注解和XML配置方式,对比了MyBatis与Hibernate的区别,指出MyBatis小巧、方便、高效的特性,以及Hibernate的强大功能和二级缓存优势。同时,文章还涵盖了MyBatis的项目集成步骤,如依赖引入、配置文件设置、日志打印等,并讨论了Mapper的多种形式和动态SQL的运用。
摘要由CSDN通过智能技术生成

1MyBatis 是一款优秀的持久层框架,它支持 SQL、存储过程以及高级映射。MyBatis 有两种用法,一个是注解,一个是XML,各有千秋

2. MyBatis与Hibernate的区别

MyBatis :

1 入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。

2 可以进行更为细致的SQL优化,可以减少查询字段。

3  缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。

4  二级缓存机制不佳

整体 : 小巧、方便、高效、简单、直接(SQL操作)、半自动

 Hibernate :

1 功能强大,数据库无关性好,对象关系(O/R)映射能力强,如果你对Hibernate相当精通,而且对Hibernate进行了适当的封装,那么你的项目整个持久层代码会相当简单,需要写的代码很少,开发速度很快,非常爽。

2 有更好的二级缓存机制,可以使用第三方缓存

3 缺点就是学习门槛不低,要精通门槛更高,而且怎么设计对象关系(O/R)映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行

3 项目集成

     1引入依赖

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->

<dependency>

    <groupId>org.mybatis</groupId>

    <artifactId>mybatis</artifactId>

    <version>3.4.6</version>

</dependency>

2 创建配置文件

在resource目录下创建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>

  <!-- 链接数据库只需要一个属性来配置文件,就会自动解析 -->

  <properties resource="jdbc.properties" />

  <!--  设置别名,然后就可以使用别名来代替前面的路径 -->       

<typeAliases>

                 <typeAlias type="com.tledu.zrz.model.User" alias="User"/>

                 <typeAlias type="com.tledu.zrz.model.Address" alias="Address"/>

        </typeAliases>

  <environments default="development">

    <environment id="development">

      <transactionManager type="JDBC"/>

      <dataSource type="POOLED">

        <property name="driver" value="${driver}"/>

        <property name="url" value="${url}"/>

        <property name="username" value="${username}"/>

        <property name="password" value="${password}"/>

      </dataSource>

    </environment>

  </environments>

  <!-- 映射文件 -->

  <mappers>

    <mapper resource="org/mybatis/example/BlogMapper.xml"/>

  </mappers>

</configuration>

创建jdbc.properties配置数据库

driver=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/erp16?useUnicode=true&characterEncoding=UTF-8

username=root

password=root

3) 准备一些测试数据

4)创建数据库操作的xml文件

这里以user为例,Address作为练习,在resource目录下创建一个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 是用于调用的时候的映射

   -->

<mapper namespace="User">

  <!--

    id : 表示调用的SQL的名字,相当于方法名

    parameterType : 表示传入参数的类型,写类全名,但是由于设置的别名,所以可以写User

    resultType : 结果集类型

   -->

        <insert id="add" parameterType="User" >

        <!-- 这里的#username 就等于是用 ? 的方式,等方法调用的时候,会传递一个参数,就会自动映射到username的属性上 -->

                 insert into t_user (username,password,nickname,type) values (#{username},#{password},#{nickname},#{type})

        </insert>

</mapper>

修改mybatis-config.xml中的映射关系

<mappers>

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

</mappers>

如果想把xml文件放到java目录中,则需要在maven的build中配置资源路径

<project>

  ...

  <build>

    ...

         <resources>

            <resource>

                <!-- directory:指定资源文件的位置 -->

                <directory>src/main/java</directory>

                <includes>

                    <!-- “**” 表示任意级目录    “*”表示任意任意文件 -->

                    <!-- mvn resources:resources :对资源做出处理,先于compile阶段  -->

                    <include>**/*.properties</include>

                    <include>**/*.xml</include>

                </includes>

                <!--  filtering:开启过滤,用指定的参数替换directory下的文件中的参数(eg. ${name}) -->

                <filtering>false</filtering>

            </resource>

            <resource>

                <directory>src/main/resources</directory>

            </resource>

     </resources>

    ...

  </build>

  ...

</project>

4 日志日志打印

4.1 引入日志的依赖

<!-- https://mvnrepository.com/artifact/log4j/log4j -->

<dependency>

    <groupId>log4j</groupId>

    <artifactId>log4j</artifactId>

    <version>1.2.17</version>

</dependency>

4.2 设置mybatis通过log4j打印日志

   <settings>

        <setting name="logImpl" value="LOG4J"/>

    </settings>

4.3 在resource目录下添加log4j.properties配置文件

### Log4j配置 ###

#定义log4j的输出级别和输出目的地(目的地可以自定义名称,和后面的对应)

#[ level ] , appenderName1 , appenderName2

log4j.rootLogger=DEBUG,console,file

#-----------------------------------#

#1 定义日志输出目的地为控制台

log4j.appender.console = org.apache.log4j.ConsoleAppender

log4j.appender.console.Target = System.out

log4j.appender.console.Threshold=DEBUG

####可以灵活地指定日志输出格式,下面一行是指定具体的格式 ###

#%c: 输出日志信息所属的类目,通常就是所在类的全名

#%m: 输出代码中指定的消息,产生的日志具体信息

#%n: 输出一个回车换行符,Windows平台为"/r/n",Unix平台为"/n"输出日志信息换行

log4j.appender.console.layout = org.apache.log4j.PatternLayout

log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#-----------------------------------#

#2 文件大小到达指定尺寸的时候产生一个新的文件

log4j.appender.file = org.apache.log4j.RollingFileAppender

#日志文件输出目录

log4j.appender.file.File=log/info.log

#定义文件最大大小

log4j.appender.file.MaxFileSize=10mb

###输出日志信息###

#最低级别

log4j.appender.file.Threshold=ERROR

log4j.appender.file.layout=org.apache.log4j.PatternLayout

log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#-----------------------------------#

#3 druid

log4j.logger.druid.sql=INFO

log4j.logger.druid.sql.DataSource=info

log4j.logger.druid.sql.Connection=info

log4j.logger.druid.sql.Statement=info

log4j.logger.druid.sql.ResultSet=info

#4 mybatis 显示SQL语句部分

log4j.logger.org.mybatis=DEBUG

#log4j.logger.cn.tibet.cas.dao=DEBUG

#log4j.logger.org.mybatis.common.jdbc.SimpleDataSource=DEBUG

#log4j.logger.org.mybatis.common.jdbc.ScriptRunner=DEBUG

#log4j.logger.org.mybatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG

#log4j.logger.java.sql.Connection=DEBUG

log4j.logger.java.sql=DEBUG

log4j.logger.java.sql.Statement=DEBUG

log4j.logger.java.sql.ResultSet=DEBUG

log4j.logger.java.sql.PreparedStatement=DEBUG

5 Mapper三种形式

常用的三种mapper

sqlSession执行对应语句,就是我们上面测试的那种
使用注解(简单sql)
利用接口代理(常用)
利用接口代理(常用)

需要xml
接口中不需要添加注解
mybatis-config.xml中添加映射配置
创建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 是用于调用的时候的映射,对应绑定的接口类

 -->

<mapper namespace="com.tledu.erp.mapper.IUserMapper">

    <insert id="add" parameterType="User" >

        <!-- 这里的#username 就等于是用 ? 的方式,等方法调用的时候,会传递一个参数,就会自动映射到username的属性上 -->

        insert into t_user (username,password,nickname) values (#{username},#{password},#{nickname})

    </insert>

    <select id="getList" resultType="User">

        select * from t_user

    </select>

    <select id="getById" parameterType="int" resultType="User">

        select * from t_user where id = #{id}

    </select>

</mapper>

在mubatis-config.xml中配置

<mapper resource="com/tledu/erp/mapper/User.xml"/>

1 #和$的区别

#{}表示一个占位符号

通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,
#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。
可以自动对值添加 ’ ’ 单引号
${}表示拼接 sql 串

通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换,
${}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value。
比如order by id  这种的,以id排序  那么这个id 是没有单引号的,就是简单的SQL拼接,所以我们应该使用${} 而不是#{}
小结:一般我们获取变量值的时候使用#{}来读取属性,如果需要进行sql拼接的时候可以使用${},使用${}的时候要注意防止sql注入

2

 paramerterType:

resultType

resultType 属性可以指定结果集的类型,它支持基本类型和实体类类型。

需要注意的是,它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须使用全限定类名。同时,当是实体类名称是,还有一个要求,实体类中的属性名称必须和查询语句中的列名保持一致,否则无法实现封装。

resultMap

通过resultMap,我们可以指定查询结果字段和实体属性字段的映射关系。

<resultMap id="userResult" type="User">

    <id column="id" property="id" />

    <result property="nickname" column="nickname" />

    <result property="schoolName" column="school_name" />

</resultMap>

3 mybatis-config.xml 配置文件

3.1 属性配置的两种方式

3.1.1 直接配置属性

<properties>

  <property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>

  <property name="jdbc.url" value="jdbc:mysql://localhost:3306/test"/>

  <property name="jdbc.username" value="root"/>

  <property name="jdbc.password" value="root"/>

</properties>

3.1.2 读取配置文件

创建db.properties

driver=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/erp16?useUnicode=true&characterEncoding=UTF-8

username=root

password=root

常用读取配置文件的方式

3.2 mapper属性

Mappers是我们所说的映射器,用于通过mybatis配置文件去找到对应的mapper文件,关于这个属性有三种用法。

         Resource

使用相对于类路径的资源如:<mapper resource="com/tledu/zrz/dao/IUserDao.xml" />

         class

使用 mapper 接口类路径

如:<mapper class="com.tledu.zrz.dao.UserDao"/>

注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。

         package

注册指定包下的所有 mapper 接口

如:<package name="com.tledu.zrz.mapper"/>

注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中,并且这里如果希望能够扫描到包下面的xml文件的话,需要在maven中进行配置。

 4动态sql

if

<select id="list" parameterType="User" resultMap="userResult">

        select  * from t_user where 1=1

        <if test="username != null and username != ''">

            and username = #{username}

        </if>

        <if test="nickname != null and nickname != ''">

            and nickname like concat('%',#{nickname},'%')

        </if>

</select>

where

在我们where条件不确定的时候,我们每次都需要加上一个1=1才能保证后面的拼接不会出现错误,使用where标签后,我们就不需要考虑拼接的问题了,直接在里面添加条件即可。通过where标签也可以让代码更具有语义化,方便维护代码

 <select id="list" parameterType="User" resultMap="userResult">

        select * from t_user where

        <where>

            <if test="username != null and username != ''">

                and username = #{username}

            </if>

            <if test="nickname != null and nickname != ''">

                and nickname like concat('%',#{nickname},'%')

            </if>

        </where>

    </select>

set

在进行更新操作的时候,也可以用set标签添加更新条件,同样我们也就不需要在进行字符串拼接了,set标签会帮我们进行拼接。   

 <update id="updateNickname">

        update t_user

        <set>

            <if test="nickname != null and nickname != ''">

                nickname = #{nickname},

            </if>

            <if test="username != null and username != ''">

                username = #{username},

            </if>

        </set>

        where id = #{id}

    </update>

 foreach

我们在开发项目中难免需要进行批量操作,这个时候就可以使用foreach进行循环添加。

例如批量插入

    <insert id="batchInsert">

        insert into t_user (username, password, nickname) VALUES

        <foreach collection="list" index="idx" item="item" separator=",">

            (#{item.username},#{item.password},#{item.nickname})

        </foreach>

    </insert>

in 查询

<select id="list" parameterType="User" resultMap="userResult">

        select * from t_user

        <where>

            <if test="user.username != null and user.username != ''">

                and username = #{user.username}

            </if>

            <if test="user.nickname != null and user.nickname != ''">

                and nickname like concat('%',#{user.nickname},'%')

            </if>

            and id in

            <foreach collection="idList" item="item" separator="," open="(" close=")">

                #{item}

            </foreach>

        </where>

    </select>

collection 需要遍历的列表
item 每一项的形参名
index 每一项索引名
separtor 分隔符
open 开始符号
close 关闭符号
5 联查

在实现1对1映射的时候,可以通过association属性进行设置。在这里有三种方式

1 使用select

 <resultMap id="address" type="Address">

        <id column="id" property="id" />

        <association property="user" column="user_id" javaType="User" select="com.tledu.erp.dao.IUser2Dao.selectById"/>

</resultMap>

property配置了实体类对应的属性
column配置了关联字段
select对应了IUser2Dao中的查询语句
在执行sql的过程中就会同时调用在IUserDao中定义的sql进行联查。

这种方式会执行两次sql语句,效率相对较低,同时还需要先在IUserDao中进行定义后才能使用,比较麻烦

2 直接进行联查,在association中配置映射字段

这里可以直接写联查,需要转换的字段可以在association中进行配置。 

  <resultMap id="address" type="Address" autoMapping="true">

        <id column="id" property="id" />

        <association property="user" column="user_id" javaType="User" >

                  <id column="user_id" property="id" />

            <result column="school_name" property="schoolName" />

        </association>

    </resultMap>

    <select id="selectOne" resultMap="address">

        select * from t_address left join t_user tu on tu.id = t_address.user_id where t_address.id = #{id}

    </select>

autoType代表自动封装,如果不填写,则需要添加所有的对应关系。

这种方式的问题是,当association需要被多次引用的时候,就需要进行多次重复的配置,所以我们还有第三种方式,引用resultMap。

.3 嵌套的resultType

<resultMap id="addressMap" type="Address" autoMapping="true">

        <id column="id" property="id"/>

        <association property="user" column="user_id" resultMap="userMap">

        </association>

    </resultMap>

    <resultMap id="userMap" type="User" autoMapping="true">

        <id column="user_id" property="id" />

        <result column="school_name" property="schoolName"/>

    </resultMap>

    <select id="selectOne" resultMap="addressMap">

        select t_address.id,

               addr,

               phone,

               postcode,

               user_id,

               username,

               password,

               nickname,

               age,

               sex,

               school_name

        from t_address

                 left join t_user tu on tu.id = t_address.user_id

        where t_address.id = #{id}

    </select>

1对多

1 使用select

这里的用法和1对1的时候一致

在AddressDao中添加

    <select id="selectByUserId" resultType="Address">

      select * from t_address where user_id = #{userId}

    </select>

在UserDao中添加

 

    <resultMap id="userResult" type="User" autoMapping="true">

        <id column="id" property="id"/>

        <result property="nickname" column="nickname"/>

        <result property="schoolName" column="school_name"/>

        <collection property="addressList" column="id" autoMapping="true" select="com.tledu.erp.dao.IAddressDao.selectByUserId" >

        </collection>

    </resultMap>

    <select id="selectById" parameterType="int" resultMap="userResult">

        select *

        from t_user

        where id = #{id}

    </select>

5.2.2 直接进行联查,在collection中配置映射字段

这里可以直接写联查,需要转换的字段可以在collection中进行配置。

 

 <resultMap id="userResult" type="User" autoMapping="true">

        <id column="id" property="id"/>

        <result property="nickname" column="nickname"/>

        <result property="schoolName" column="school_name"/>

        <collection property="addressList" column="phone" ofType="Address" autoMapping="true">

            <id column="address_id" property="id" />

        </collection>

    </resultMap>

    <select id="selectById" parameterType="int" resultMap="userResult">

        select tu.id,

               username,

               password,

               nickname,

               age,

               sex,

               school_name,

               ta.id as address_id,

               addr,

               phone,

               postcode,

               user_id

        from t_user tu

                 left join t_address ta on tu.id = ta.user_id

        where tu.id = #{id}

    </select>

autoMapping代表自动封装,如果不填写,则需要添加所有的对应关系。

这里需要配置ofType来指定返回值类型

这种方式的问题是,当collection需要被多次引用的时候,就需要进行多次重复的配置,所以我们还有第三种方式,引用resultMap。

5.1.3 嵌套的resultType

 <resultMap id="userResult" type="User" autoMapping="true">

        <!--        <id column="id" property="id"/>-->

        <result property="nickname" column="nickname"/>

        <result property="schoolName" column="school_name"/>

        <collection property="addressList" column="phone" ofType="Address" resultMap="addressResultMap" autoMapping="true">

        </collection>

    </resultMap>

    <resultMap id="addressResultMap" type="Address" autoMapping="true">

        <id column="address_id" property="id" />

    </resultMap>

    <select id="selectById" parameterType="int" resultMap="userResult">

        select tu.id,

               username,

               password,

               nickname,

               age,

               sex,

               school_name,

               ta.id as address_id,

               addr,

               phone,

               postcode,

               user_id

        from t_user tu

                 left join t_address ta on tu.id = ta.user_id

        where tu.id = #{id}

    </select>


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值