请选择 进入手机版 | 继续访问电脑版

热点推荐

    查看: 80|回复: 0

    3.Mybatis-03 Mybatis 连接池与事务深入,Mybatis 的动态 SQL 语句,Mybatis

    [复制链接]

    该用户从未签到

    651

    主题

    651

    帖子

    1953

    积分

    金牌会员

    Rank: 6Rank: 6

    积分
    1953
    发表于 7 天前 | 显示全部楼层 |阅读模式
    主要内容* t' D0 a( P3 a( ]) r: V
    $ I% e5 E9 y8 F0 Q
      7 ~0 [) d  `9 |  ?# s; h- n
    • Mybatis 连接池与事务深入0 T2 ?2 |) D8 ~3 L  x7 G* ~
    • Mybatis 的动态 SQL 语句3 U7 |) M, V, c8 g* Q, _/ S
    • 一对一查询(多对一)" n+ ?# ^% o0 t  Y. m
    • Mybatis 多表查询之一对多
      3 }: U- K# R3 ^9 A1 \- V8 ^
    • Mybatis 多表查询之多对多  y2 R) \( a  _% r7 @4 _
    Mybatis 连接池与事务深入" Q; y$ |; k0 P" Q

    ; _8 V  R- W7 g# C% i9 U, e1.1 Mybatis 的连接池技术5 B! p5 T8 U) r- F0 b
    * ^+ k9 J6 u1 h$ `( Z5 X8 `2 G; P* \
    Mybatis采用的是自己的连接池技术。在 Mybatis 的 SqlMapConfig.xml 配置文件中, 通过来实现 Mybatis 中连接池的配置。
    : m2 [3 I* G' E$ o. T4 s1.1.1 Mybatis 连接池的分类$ e  z7 \0 _# {9 M- i4 Y" U$ a. H
    8 G* ?' [* V( V) N" ^
    在 Mybatis 中我们将它的数据源 dataSource 分为以下几类:, f8 q* F+ h- S% w, `: X
    8 @8 C2 W' y+ G: U

    ) ^0 Q2 l, j" H3 @  b8 U3 j可以看出 Mybatis 将它自己的数据源分为三类:
    # J! L& J, G8 C& m% z4 tUNPOOLED 不使用连接池的数据源; j8 x5 U+ \6 r  i
    POOLED 使用连接池的数据源
    ) R. l/ {5 Q, j( Q3 J3 }: dJNDI 使用 JNDI 实现的数据源0 K4 L: ^- u: q( q9 g( {3 s
    具体结构如下:+ c- [1 z+ m4 {) g, Z' a
    ( N2 \% @% r* W+ v" X% {
    . k# `+ h: e/ {0 a6 S
    相应地, MyBatis 内部分别定义了实现了 java.sql.DataSource 接口的 UnpooledDataSource,
    # q+ P( Q$ `1 S0 c0 O) ?5 n# MPooledDataSource 类来表示 UNPOOLED、 POOLED 类型的数据源。
    % I& i* p1 U. E& |' p8 e: \

    8 R* f/ ?% F7 w6 K: \1 l6 Z在这三种数据源中,我们一般采用的是 POOLED 数据源(很多时候我们所说的数据源就是为了更好的管理数据库连接,也就是我们所说的连接池技术) 。
    : t& \3 u2 ]" k4 [/ w2 [& U0 c7 {1.1.2 Mybatis 中数据源的配置1 r) J' H  q7 P8 ?# r# p: m
      z; {5 {9 k8 R) }
    我们的数据源配置就是在 SqlMapConfig.xml 文件中, 具体配置如下:
    , S/ ?& q! Z8 d' _+ F: P  v        MyBatis 在初始化时, 根据的 type 属性来创建相应类型的的数据源 DataSource,即:, N2 m# l& N* s! Q1 k; [6 }
    type=”POOLED”: MyBatis 会创建 PooledDataSource 实例
    - Q  S; j9 E3 F% Otype=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例
    ( W3 p) ~0 ^, |% S; ^: @  jtype=”JNDI”: MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用) L2 M: r7 g" H& M6 u
    1.1.3 Mybatis 中 DataSource 的存取
    7 V" w" r+ V; H8 j7 ^( F" I7 g! a7 ?* B+ g& D
    MyBatis 是 通 过 工 厂 模 式 来 创 建 数 据 源 DataSource 对 象 的 , MyBatis 定 义 了 抽 象 的 工 厂 接" b8 C1 `+ R+ w. Y  W
    口:org.apache.ibatis.datasource.DataSourceFactory,通过其 getDataSource()方法返回数据源DataSource。
    , m: I+ J7 w5 i3 V; G1.1.4 Mybatis 中连接的获取过程分析4 i# b6 p7 u' v; x, @* u4 R

    . r* z4 ^5 C% f- I! E! O9 ^当我们需要创建 SqlSession 对象并需要执行 SQL 语句时,这时候 MyBatis 才会去调用 dataSource 对象2 t+ h/ j" p6 k6 p/ r- h2 b' D) h, d
    来创建 java.sql.Connection对象。也就是说, java.sql.Connection对象的创建一直延迟到执行 SQL语句$ r3 A1 t- T0 W. \- B$ z8 h
    的时候。
    $ n7 m3 J1 q. ?1.2 Mybatis 的事务控制7 h; ^1 C4 i! Q6 W

    9 ~4 h+ s% Z9 E  S4 @5 n1.2.1 JDBC 中事务的回顾
    , ?! z2 X3 N8 ^2 b( ?* E
    8 I- H7 S% }8 K" j. R) R在 JDBC 中我们可以通过手动方式将事务的提交改为手动方式,通过 setAutoCommit()方法就可以调整。0 r7 T' J- T6 n) i% O
    通过 JDK 文档,我们找到该方法如下:
    2 E8 {( v3 n1 c8 g- w, _5 Y9 M" h9 M- _3 f9 k

    5 d; |5 T* a; J3 O2 g  v3 P. L那么我们的 Mybatis 框架因为是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的
    0 _$ u5 k9 }! osetAutoCommit()方法来设置事务提交方式的。
    8 e6 g! W/ o. g1.2.2 Mybatis 中事务提交方式
    / R% `  U! L" @  K& v' b: V( N* t
    Mybatis 中事务的提交方式,本质上就是调用 JDBC 的 setAutoCommit()来实现事务控制。
    0 v! w9 F% X+ b1.2.3 Mybatis 自动提交事务的设置% y% p* K8 \. W5 v$ }
    4 J, `- v6 }- u% e2 j1 }2 u; S2 A
    factory.openSession(true);
    - C# k8 }4 l7 U2 D. z& F@Test    public void test8() throws Exception {        //1.读取配置文件        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");        //2.创建 SqlSessionFactory 的构建者对象        SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();        //3.使用构建者创建工厂对象 SqlSessionFactory        SqlSessionFactory factory = factoryBuilder.build(inputStream);        //4.使用 SqlSessionFactory 生产 SqlSession 对象 并开启事务自动提交        SqlSession session = factory.openSession(true);        //5.使用 SqlSession 创建 dao 接口的代理对象        IUserDao iuserDao = session.getMapper(IUserDao.class);        //6.使用代理对象执行保存方法        User user = new User();        user.setUsername("事务自动提交");        user.setAddress("北京市顺义区");        user.setSex("男");        user.setBirthday(new Date());        System.out.println("保存操作之前: "+user);        iuserDao.saveUser(user);        System.out.println("保存操作之后: "+user);        //7.释放资源        session.close();        inputStream.close();    }Mybatis 的动态 SQL 语句
    - n/ Z8 s, ?- Z$ A/ V" W
    ' |9 y. S1 I  Q2.1 动态 SQL 之标签- _3 q6 |) F6 U0 _
    ; V7 T7 L1 j8 z. M7 Q
    我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如在 id 如果不为空时可以根据 id 查询,, B7 V  r" j, Q& _; M0 L5 Z( r
    如果 username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。! v6 X6 B" P: D+ j' }! t
    2.1.1 持久层 Dao 接口
    0 U+ j, Y2 G, Y- U4 S8 Y7 b. z; G+ T7 F; L
    List findByUser(User user);2.1.2 持久层 Dao 映射配置
    1 w5 S6 t0 r! V( h) w7 h5 x  G5 ?% Y4 J+ U# G. c$ n* J
      select * from user where 1=1  and username like #{username}  and address like #{address}
    注意: 标签的test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法。" i  p; Z' I8 ]% T1 J9 y
    另外要注意 where 1=1 的作用~!$ `, ?& x# }( q! r) h
    2.2 动态 SQL 之标签
    ' v0 d+ x" X* {" z' R6 Z& M
    ( e! a7 I1 R. a0 e  G7 L为了简化上面 where 1=1 的条件拼装,我们可以采用标签来简化开发。2 A, E! j6 Q- j2 o: d
    2.2.1 持久层 Dao 映射配置* |2 P( e& J4 W6 a" h- V) x
    4 A& i! P$ w  _- Z) a' k+ ^
    抽取重复的sql语句
    8 Y* W# {  Z' q8 w+ o1 V' {+ L            select * from user      and username like #{username}  and address like #{address}2.3 动态标签之标签
    & O. X0 `* `! u1 c) v
      l. i4 a7 n" j  B9 L! [2.3.1 需求0 n( Z& `- e; E9 g- d! s

    7 M) @/ Z& j0 i4 O7 M传入多个 id 查询用户信息,用下边两个 sql 实现:; {  z6 m& {( z
    SELECT * FROM USERS WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16)
    $ X. B, ^# m  b6 eSELECT * FROM USERS WHERE username LIKE '%张%' AND id IN (10,89,16)
    6 P( j' ]$ f% T1 J. {这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。
      I* S3 I! k) v7 m这样我们将如何进行参数的传递?
    + J! j) R5 Q. |1 S, Y' J8 K2.3.1.1 在 QueryVo 中加入一个 List 集合用于封装参数8 H2 r5 z% P6 D  _7 g$ }3 U4 z3 W

    & O& o: h. t0 l4 j- t/ f/**** Title: QueryVo
    4 N. M( |3 t; Y, r* Description: 查询的条件
    / r; r0 |0 V6 v, L) _1 p2 Z: j* j* Company: http://www.itheima.com/ 0 a6 d5 q: }8 V
    */public class QueryVo implements Serializable {    private List ids;    public List getIds() {        return ids;    }    public void setIds(List ids) {        this.ids = ids;    }}2.3.2 持久层 Dao 接口# n3 u- y( h% }

    + z8 u- ?4 H+ R* c$ q/*** 根据 id 集合查询用户* @param vo* @return*/List findInIds(QueryVo vo);2.3.3 持久层 Dao 映射配置0 R- t$ r" v! V0 E2 i# z

    7 ]  v. F7 c1 I$ H              #{uid}      SQL 语句:select 字段 from user where id in (?)
    % c5 g9 N4 ]2 [2 f2 v标签用于遍历集合,它的属性:
    3 Q& n$ k, A; w) t5 q! \% D; acollection:代表要遍历的集合元素,注意编写时不要写#{}
    ( x* B# K+ z2 M5 P$ ^open:代表语句的开始部分  q& w/ Z0 S2 O9 \) T' |+ \2 l
    close:代表结束部分
    4 Y8 K/ F7 m. _$ D- Eitem:代表遍历集合的每个元素,生成的变量名4 p/ q8 }. I# i& H
    sperator:代表分隔符
    5 ^! y$ E: ^, R+ y3 s2.4 Mybatis 中简化编写的 SQL 片段: F9 P- P5 d3 J" `6 B( H; y

    7 c) l1 u1 v2 \( U3 lSql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的。4 H: z: `" j8 o7 Z- q: v$ E9 x1 n
    2.4.1 定义代码片段
      R1 f) u9 R! [  s# W& W4 i9 x: c5 x9 g* Y) |
    select * from user2.4.2 引用代码片段
    # }7 m# K4 T: g  a
    & O4 i8 p  C2 V# ]            where id = #{uid}Mybatis 多表查询之一对多
    3 f' @# I! H: r7 ^, e
    6 k0 h8 e1 |2 l, C9 Q3 l+ V本次案例主要以最为简单的用户和账户的模型来分析 Mybatis 多表关系。用户为 User 表,账户为 Account6 y" Q9 F- O* X; _9 J) G! G
    表。一个用户( User)可以有多个账户( Account)。具体关系如下:3 b. d) e1 O4 }. k$ q. E

      W0 u" k' J* P

    6 q. z  }2 x# z4 c* I3 @需求; e# `& S. T: W
    查询所有账户信息,关联查询下单用户信息。; n  |. q. r1 k* G3 x7 ?8 ^
    注意:( h1 b  A) K6 l- n# W
    因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询。如
    # o! F$ @3 S% k2 U果从用户信息出发查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户。# [7 g4 j: q& n3 @" M
    3.1.1 方式一
    2 s8 s$ _2 A+ z9 z9 u$ f0 V1 c% ]1 w2 F) ~% S9 G( d
    3.1.1.1 定义账户信息的实体类
    3 b# W8 z# x! ^* @5 Q5 f
    + ~1 N2 L) T0 F3 ~; hpackage com.ding.domain;import java.io.Serializable;public class Account implements Serializable {    private Integer id;    private Integer uid;    private Double money;    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    public Integer getUid() {        return uid;    }    public void setUid(Integer uid) {        this.uid = uid;    }    public Double getMoney() {        return money;    }    public void setMoney(Double money) {        this.money = money;    }    @Override    public String toString() {        return "Account{" +                "id=" + id +                ", uid=" + uid +                ", money=" + money +                '}';    }}3.1.1.2 编写 Sql 语句9 ~1 _  k0 t, C
    1 j2 O$ u" U- _, M2 ~2 H
    实现查询账户信息时,也要查询账户所对应的用户信息。
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    快速回复 返回顶部 返回列表