精华内容
下载资源
问答
  • ET 之网络框架

    千次阅读 2021-01-28 15:20:38
    ET包含了3套Socket连接,TCP,KCP,WebSocket 首先,TCP肯定是长连接最常用的协议了,不多做解释。而KCP呢,其实是 林伟 大神封装的可靠UDP,传输能力要比TCP强不少。而WebSocket,一般是H5常用,所以我不太了解,...

    一.前言

    阅读这篇文章要求对ET框架的ECS结构有所了解

    ET框架简介

    ET是一个开源的游戏客户端(基于unity3d)服务端双端框架,服务端是使用C# .net core开发的分布式游戏服务端,其特点是开发效率高,性能强,双端共享逻辑代码,客户端服务端热更机制完善,同时支持可靠udp tcp websocket协议,支持服务端3D recast寻路等等

    ET是主要以双端框架著称,所以可以想象一下网络其实是它的核心,我相信,应该是是作者付出了最多心血的杰作,下面我们就来拆解一下ET的网络框架

    ET包含了3套Socket连接,TCP,KCP,WebSocket

    首先,TCP肯定是长连接最常用的协议了,不多做解释。而KCP呢,其实是 林伟 大神封装的可靠UDP,传输能力要比TCP强不少。而WebSocket,一般是H5常用,所以我不太了解,这里也不多说。但是框架把三种socket连接整合到一起,整个结构是是分清晰的。值得我们去学习。

    Network目录:Model/Module/Message/Network

    核心代码就是NetworkComponent类 + KCP,TCP,WebSocket目录

    二.结构详解

    1.NetOuterComponentSystem

    System就是ET的ECS系统中的S,主要功

    展开全文
  •   假设有如下一种情况,红为模型预测的检测region proposal,蓝为真实的检测ground truth。 可以看见,尽管红正确地从图像中识别到了飞机,但是却并没有很好地标识出检测的位置(预测与真实IoU过...

    一、为什么需要边框回归

      假设有如下一种情况,红框为模型预测的检测框region proposal,蓝框为真实的检测框ground truth

    在这里插入图片描述

    可以看见,尽管红框正确地从图像中识别到了飞机,但是却并没有很好地标识出检测框的位置(预测框与真实框IoU过低)。此时,便可以通过边框回归Bounding Box Regression实现一种“微调”的策略,将预测框尽量调整到与真实框近似,以提高模型预测的效果。

    二、边框回归的调整策略

      边框回归的调整策略总结一下就是两个词:平移缩放
      假设模型输出的预测框信息可以如下表示:

    P = [Px, Py, Pw, Ph]
    # Px: 中心点横坐标
    # Py: 中心点纵坐标
    # Pw: 宽度
    # Ph: 高度
    

    那么所谓平移,就是针对Px, Py进行一定程度的加减,使之更加接近于真实框的中心点坐标Tx, Ty。所谓缩放,也就是针对Pw, Ph进行一定比例的乘除,使之更加接近于真实框的宽度Tw和高度Th。即:

    T = [Tx, Ty, Tw, Th]
    # Tx = Px + dx
    # Ty = Py + dy
    # Tw = Pw * dw
    # Th = Ph * dh
    

    三、论文里怎么说

    3.1 平移量与缩放量定义

      在论文中,对于中心点坐标的平移量和宽度高度的缩放量都有着更为详细的定义:
    { T x = P x + Δ x T y = P y + Δ y , { T w = P w S w T h = P h S h \begin{cases} T_x=P_x+\Delta_x\\ T_y=P_y+\Delta_y \end{cases},\qquad \begin{cases} T_w=P_wS_w\\ T_h=P_hS_h \end{cases} {Tx=Px+ΔxTy=Py+Δy,{Tw=PwSwTh=PhSh
    其中, Δ x = P w d x ( P ) ,   Δ y = P h d y ( P ) ,   S w = e d w ( P ) ,   S h = e d h ( P ) \Delta_x=P_wd_x(P),\ \Delta_y=P_hd_y(P),\ S_w=e^{d_w(P)},\ S_h=e^{d_h(P)} Δx=Pwdx(P), Δy=Phdy(P), Sw=edw(P), Sh=edh(P)。那么,所谓的边框回归,其实也就是让模型学习四个参数 d x ( P ) , d y ( P ) , d w ( P ) , d h ( P ) d_x(P),d_y(P),d_w(P),d_h(P) dx(P),dy(P),dw(P),dh(P),使预测框能够在输出前进行如上变换,从而更接近于真实值。

    3.2 损失函数

      根据预测框与真实框的坐标大小信息,我们可以计算出预测框经过平移缩放变换到真实框所需要的真实平移量参数与缩放量参数:
    { t x = T x − P x P w t y = T y − P y P h t w = log ⁡ T w P w t h = log ⁡ T h P h \begin{cases} t_x=\frac{T_x-P_x}{P_w}\\t_y=\frac{T_y-P_y}{P_h}\\t_w=\log{\frac{T_w}{P_w}}\\t_h=\log{\frac{T_h}{P_h}} \end{cases} tx=PwTxPxty=PhTyPytw=logPwTwth=logPhTh
      将需要学习的目标函数 d ( P ) d(P) d(P)改写为 w T ϕ P w^T\phi_P wTϕP ϕ P \phi_P ϕP是特征向量),再结合上面计算的真实参数量即可得到边框回归的损失函数如下:
    L = ∑ i ( x , y , w , h ) ( w i T ϕ P − t i ) 2 L=\sum^{(x,y,w,h)}_i(w^T_i\phi_P-t_i)^2 L=i(x,y,w,h)(wiTϕPti)2
    加入正则化参数,则可得模型的目标函数如下:
    w = arg min ⁡ w ∑ i ( x , y , w , h ) ( w i T ϕ P − t i ) 2 + λ ∥ w ∥ w=\argmin_{w}{\sum^{(x,y,w,h)}_i(w^T_i\phi_P-t_i)^2+\lambda\|w\|} w=wargmini(x,y,w,h)(wiTϕPti)2+λw
    使用梯度下降算法等优化算法即可对上述目标函数进行求解。

    3.3 为什么是线性回归

      根据论文描述,边框回归算法只适用于对预测框进行微调,即当IoU不低于某个阙值时才可发挥作用。而当IoU足够高时,缩放变换可视为线性变换,从而可以考虑使用线性回归模型对参数进行求解。

      那么为什么当IoU足够高时缩放可视为线性变换呢?

    在这里插入图片描述

      如上图所示,当 x → 0 x\to 0 x0时,有 x = log ⁡ ( x + 1 ) x=\log(x+1) x=log(x+1)。对缩放变换公式进行变形可得:
    d w ( P ) = log ⁡ T w P w = log ⁡ P w + T w − P w P w = log ⁡ ( 1 + T w − P w P w ) d h ( P ) = log ⁡ T h P h = log ⁡ P h + T h − P h P h = log ⁡ ( 1 + T h − P h P h ) \begin{aligned} d_w(P)=\log{\frac{T_w}{P_w}}&=\log{\frac{P_w+T_w-P_w}{P_w}}\\&=\log(1+\frac{T_w-P_w}{P_w}) \end{aligned}\\ \begin{aligned} d_h(P)=\log{\frac{T_h}{P_h}}&=\log{\frac{P_h+T_h-P_h}{P_h}}\\&=\log(1+\frac{T_h-P_h}{P_h}) \end{aligned} dw(P)=logPwTw=logPwPw+TwPw=log(1+PwTwPw)dh(P)=logPhTh=logPhPh+ThPh=log(1+PhThPh)
      可见,当IoU足够高时,也就是 T w T_w Tw P w P_w Pw近似、 T h T_h Th P h P_h Ph近似时,有:
    d w ( P ) = T w − P w P w , d h ( P ) = T h − P h P h d_w(P)=\frac{T_w-P_w}{P_w},\quad d_h(P)=\frac{T_h-P_h}{P_h} dw(P)=PwTwPw,dh(P)=PhThPh
    近似于一个线性变换,因此可以使用线性回归进行求解。

    四、论文中为什么这样定义平移量和缩放量

    4.1 平移量中为什么加入宽和高

      平移量中加入宽和高是基于卷积神经网络的尺度不变性,即相同的物体在不同尺度的图像中通过CNN提取出的特征图应该一致。至于CNN尺度不变性的解释,学术界似乎尚存争议,此处不作过多解释。

      假设有如下两种尺度不同的图像:

    在这里插入图片描述

    在这里插入图片描述

      根据CNN的尺度不变性,两张图片通过CNN提取出的特征图 ϕ P \phi_P ϕP应当相等,带入同一个模型 d x ( P ) = w x ϕ P ,   d y ( P ) = w y ϕ P d_x(P)=w_x\phi_P,\ d_y(P)=w_y\phi_P dx(P)=wxϕP, dy(P)=wyϕP,则可以知道两张图的平移量也应当相等。然后根据如上图像展示,可以发现两图预测框到真实框的平移量显然不等,为了保证函数值的唯一性,平移量的定义才考虑加入了检测框的宽度和高度。

    4.2 缩放量为什么采用e的幂

      缩放量采用e的幂次方主要有两个考虑:

      1)保证缩放的倍率恒大于0

      2)采用e的幂才能依靠 lim ⁡ x → 0 log ⁡ ( x + 1 ) = x \lim_{x\to 0}\log(x+1)=x limx0log(x+1)=x的性质,将缩放近似为一个线性变换

    展开全文
  • 在下文中为你解释。 这其中涉及到了 Java 线程的同步互斥机制。例如如何让 T1 在 T2 和 T3 之前运行,如何让 T2 和 T3 都执行完毕之后开启 T4 线程。 如何来描述图 1 中所示的场景呢?可以采用 XML 的格式来描述我们...

    2006 年 8 月 14 日

    Java 提供了语言级别的线程支持,所以在 Java 中使用多线程相对于 C,C++ 来说更简单便捷,但本文并不是介绍如何在 Java 中使用多线程来来解决诸如 Web services, Number crunching 或者 I/O processing 之类的问题。在本文中,我们将讨论如何实现一个 Java 多线程的运行框架以及我们是如何来控制线程的并发同步以及顺序执行的。

    图 1. 线程场景

    13f465a3dd1a19a13082ab3437accfcc.png

    这幅图中节点代表一个 single Thread,边代表执行的步骤。

    整幅图代表的意思是,ROOT 线程执行完毕后执行 T1 线程,T1 执行完毕后并发的执行 T2 和 T3。而从 T2 和 T3 指向 T4 的两条边表示的是 T4 必须等 T2 和 T3 都执行完毕以后才能开始执行。剩下的步骤以此类推,直到 END 作为整个过程的结束。当然,这只是个简略的示意图,可能面对的一个线程场景会有上百个线程。还有,你可以观察到这整个场景只有一个入口点和一个出口点,这意味着什么?在下文中为你解释。

    这其中涉及到了 Java 线程的同步互斥机制。例如如何让 T1 在 T2 和 T3 之前运行,如何让 T2 和 T3 都执行完毕之后开启 T4 线程。

    05ac63f463130bd1876c1af927ae88a3.png

    c6ccbc96c20bebb0d73e8e6368158ef5.png

    如何来描述图 1 中所示的场景呢?可以采用 XML 的格式来描述我们的模型。我定义一个“Thread” element 来表示线程。

    其中 ID 是线程的唯一标识符,PRETHREAD 便是该线程的直接先决线程的ID,每个线程 ID 之间用逗号隔开。

    在 Thread 这个 element 里面可以加入你想要该线程执行任务的具体信息。

    实际上模型的描述是解决问题非常重要的一个环节,整个线程场景可以用一种一致的形式来描述,作为 Java 多线程并发控制框架引擎的输入。也就是将线程运行的模式用 XML 来描述出来,这样只用改动 XML 配置文件就可以更改整个线程运行的模式,不用改动任何的源代码。

    05ac63f463130bd1876c1af927ae88a3.png

    c6ccbc96c20bebb0d73e8e6368158ef5.png

    对于 Java 多线程的运行框架来说,我们将采用“外”和“内”的两种模式来实现。

    05ac63f463130bd1876c1af927ae88a3.png

    c6ccbc96c20bebb0d73e8e6368158ef5.png

    图 2. 静态类图

    03c07359f5dbbf0e3743f7813007f51f.gif

    Thread 是工作线程。ThreadEntry 是 Thread 的包装类,prerequisite 是一个 HashMap,它含有 Thread 的先决线程的状态。如图1中显示的那样,T4 的先决线程是 T2 和 T3,那么 prerequisite 中就包含 T2 和 T3 的状态。TestScenario 中的 threadEntryList 中包含所有的 ThreadEntry。

    图 3. 线程执行场景

    00976a8b976252f7b9d005f9c25ad896.gif

    TestScenario 作为主线程,作为一个“外”在的监控者,不断地轮询 threadEntryList 中所有 ThreadEntry 的状态,当 ThreadEntry 接受到 isReady 的查询后查询自己的 prerequisite,当其中所有的先决线程的状态为“正常结束时”,它便返回 ready,那么 TestScenario 便会调用 ThreadEntry 的 startThread() 方法授权该 ThreadEntry 运行线程,Thread 便通过 run() 方法来真正执行线程。并在正常执行完毕后调用 setPreRequisteState() 方法来更新整个 Scenario,threadEntryList 中所有 ThreadEntry 中 prerequisite 里面含有该 Thread 的状态信息为“正常结束”。

    图 4. 状态更改的过程

    5ad6f6b3dc34fbcb3ba7d5f8f102991d.png

    如图 1 中所示的 T4 的先决线程为 T2 和 T3,T2 和 T3 并行执行。如图 4 所示,假设 T2 先执行完毕,它会调用 setPreRequisteState() 方法来更新整个 Scenario, threadEntryList 中所有 ThreadEntry 中 prerequisite 里面含有该 T2 的状态信息为“正常结束”。此时,T4 的 prerequisite 中 T2 的状态为“正常结束”,但是 T3 还没有执行完毕,所以其状态为“未完毕”。所以 T4 的 isReady 查询返回为 false,T4 不会执行。只有当 T3 执行完毕后更新状态为“正常结束”后,T4 的状态才为 ready,T4 才会开始运行。

    其余的节点也以此类推,它们正常执行完毕的时候会在整个的 scenario 中广播该线程正常结束的信息,由主线程不断地轮询各个 ThreadEntry 的状态来开启各个线程。

    这便是采用主控线程轮询状态表的方式来控制 Java 多线程运行框架的实现方式之一。

    优点:概念结构清晰明了,实现简单。避免采用 Java 的锁机制,减少产生死锁的几率。当发生异常导致其中某些线程不能正常执行完毕的时候,不会产生挂起的线程。

    缺点:采用主线程轮询机制,耗费 CPU 时间。当图中的节点太多的(n>??? 而线程单个线程执行时间比较短的时候 t?? 需要进一步研究)时候会产生线程启动的些微延迟,也就是说实时性能在极端情况下不好,当然这可以另外写一篇文章来专门探讨。

    05ac63f463130bd1876c1af927ae88a3.png

    c6ccbc96c20bebb0d73e8e6368158ef5.png

    相对于“外”-主线程轮询机制来说,“内”采用的是自我控制连锁触发机制。

    图 5. 锁机制的静态类图

    e2ff243b7f362f2066b95741aecd1321.gif

    Thread 中的 lock 为当前 Thread 的 lock,lockList 是一个 HashMap,持有其后继线程的 lock 的引用,getLock 和 setLock 可以对 lockList 中的 Lock 进行操作。其中很重要的一个成员是 waitForCount,这是一个引用计数。表明当前线程正在等待的先决线程的个数,例如图 1 中所示的 T4,在初始的情况下,他等待的先决线程是 T2 和 T3,那么它的 waitForCount 等于 2。

    图 6. 锁机制执行顺序图

    1fcc906ff46ce0051ab83f2f9f0a82ac.gif

    当整个过程开始运行的时候,我们将所有的线程 start,但是每个线程所持的 lock 都处于 wait 状态,线程都会处于 waiting 的状态。此时,我们将 root thread 所持有的自身的 lock notify,这样 root thread 就会运行起来。当 root 的 run 方法执行完毕以后。它会检查其后续线程的 waitForCount,并将其值减一。然后再次检查 waitForCount,如果 waitForCount 等于 0,表示该后续线程的所有先决线程都已经执行完毕,此时我们 notify 该线程的 lock,该后续线程便可以从 waiting 的状态转换成为 running 的状态。然后这个过程连锁递归的进行下去,整个过程便会执行完毕。

    我们还是以 T2,T3,T4 为例,当进行 initThreadLock 过程的时候,我们可以知道 T4 有两个直接先决线程 T2 和 T3,所以 T4 的 waitForCount 等于 2。我们假设 T3 先执行完毕,T2 仍然在 running 的状态,此时他会首先遍历其所有的直接后继线程,并将他们的 waitForCount 减去 1,此时他只有一个直接后继线程 T4,于是 T4 的 waitForCount 减去 1 以后值变为 1,不等于 0,此时不会将 T4 的 lock notify,T4 继续 waiting。当 T2 执行完毕之后,他会执行与 T3 相同的步骤,此时 T4 的 waitForCount 等于 0,T2 便 notify T4 的 lock,于是 T4 从 waiting 状态转换成为 running 状态。其他的节点也是相似的情况。

    当然,我们也可以将整个过程的信息放在另外的一个全局对象中,所有的线程都去查找该全局对象来获取各自所需的信息,而不是采取这种分布式存储的方式。

    优点:采用 wait&notify 机制而不采用轮询的机制,不会浪费CPU资源。执行效率较高。而且相对于“外”-主线程轮询的机制来说实时性更好。

    缺点:采用 Java 线程 Object 的锁机制,实现起来较为复杂。而且采取一种连锁触发的方式,如果其中某些线程异常,会导致所有其后继线程的挂起而造成整个 scenario 的运行失败。为了防止这种情况的发生,我们还必须建立一套线程监控的机制来确保其正常运行。

    05ac63f463130bd1876c1af927ae88a3.png

    c6ccbc96c20bebb0d73e8e6368158ef5.png

    下面的图所要表达的是这样一种递归迭代的概念。例如在图1 中展示的那样,T1 这个节点表示的是一个线程。现在,忘掉线程这样一个概念,将 T1 抽象为一个过程,想象它是一个银河系,深入到 T1 中去,它也是一个许多子过程的集合,这些子过程之间的关系模式就如图 1 所示那样,可以用一个图来表示。

    图 7. 嵌套子过程

    730ca3ee5932bbbbe8519a91bccef730.png

    可以想象一下这是怎样的一个框架,具有无穷扩展性的过程框架,我们只用定义各个过程之间的关系,我们不用关心过程是怎样运行的。事实上,可以在最终的节点上指定一个实际的工作,比如读一个文件,或者submit一个JCL job,或者执行一条sql statement。

    其实,按照某种遍历规则,完全可以将这种嵌套递归的结构转化成为一个一层扁平结构的图,而不是原来的分层的网状结构,但是我们不这样做的原因是基于以下的几点考虑:

    如果这样做,会导致图节点太多,边太多,令人眼花缭乱。

    不这样做更主要的原因是每一个场景,如图 7 中的 T1,T13,是状态聚集的一个单元,具有高复用性和可靠性。

    框架是高度抽象的,它实际的执行可以是分布式的,一个单元可以是一个系统,作为和其他系统的分界标志。

    实际上,这是一个状态聚集的层次控制框架,我们可以依赖此框架来执行自主运算。我们将在其它的文章中来讨论它的应用。

    05ac63f463130bd1876c1af927ae88a3.png

    c6ccbc96c20bebb0d73e8e6368158ef5.png

    本文介绍了一种 Java 多线程并发控制的框架,并给出了其两种实现的模型,它们有各自的优缺点,有各自的适用范围。当需要进行 Java 线程的并发控制的时候,可以作为参考。

    developerWorks Java 专区 Joseph Hartal,Ze'ev Bubis 的文章:使你轻松得进行多线程应用程序编程

    developerWorks Java 专区 Alex Roetter 的文章:编写多线程的Java应用程序

    developerWorks Java 专区 Neel V. Kumar 的文章:Java 程序中的多线程

    展开全文
  • 横切关注点:从每个方法中抽取出来的一类非核心业务代码。 2.切面:封装横切信息点的类,每个关注点体现为一个通知方法。 3.通知:切面必须要完成的各个具体工作,也就是切面里的一个个方法。 4.目标:被通知的...

    SSM框架(白痴都看完都会)


    介绍SSM框架<原理>

    一、什么是SSM框架?

    SSM框架是spring、spring MVC 、和mybatis框架的整合,是标准的MVC模式。标准的SSM框架有四层,分别是dao层(mapper),service层,controller层和View层。使用spring实现业务对象管理,使用spring MVC负责请求的转发和视图管理,mybatis作为数据对象的持久化引擎。

    1)持久层:dao层(mapper)层
    作用:主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此。

    • Dao层首先设计的是接口,然后再Spring的配置文件中定义接口的实现类。
    • 然后可以在模块中进行接口的调用来进行数据业务的处理。(不在关心接口的实现类是哪个类)
    • 数据源的配置以及有关数据库连接的参数都在Spring的配置文件中进行配置。

    2)业务层:Service层
    作用:Service层主要负责业务模块的逻辑应用设计。

    • 先设计接口然后再设计实类,然后再在Spring的配置文件中配置其实现的关联。(业务逻辑层的实现具体要调用到自己已经定义好的Dao的接口上)这样就可以在应用中调用Service接口来进行业务处理。
    • 建立好Dao之后再建立service层,service层又要在controller层之下,因为既要调用Dao层的接口又要提供接口给controller层。每个模型都有一个service接口,每个接口分别封装各自的业务处理的方法。

    3)表现层:Controller层(Handler层)
    作用:负责具体的业务模块流程的控制。

    • 配置也同样是在Spring的配置文件里面进行,
    • 调用Service层提供的接口来控制业务流程。
    • 业务流程的不同会有不同的控制器,在具体的开发中可以将我们的流程进行抽象的归纳,设计出可以重复利用的子单元流程模块。

    4)View层
    作用:主要和控制层紧密结合,主要负责前台jsp页面的表示。

    各层之间的联系

    这里是引用
    DAO层,Service层这两个层次都可以单独开发,互相的耦合度很低,完全可以独立进行,这样的一种模式在开发大项目的过程中尤其有优势,Controller,View层因为耦合度比较高,因而要结合在一起开发,但是也可以看作一个整体独立于前两个层进行开发。这样,在层与层之前我们只需要知道接口的定义,调用接口即可完成所需要的逻辑单元应用,一切显得非常清晰简单。

    1.Spring

    Spring里面的IOC容器和AOP是我们平时使用最多的。
    1)IOC(控制反转)
    它可以装载bean,也是一种降低对象之间耦合关系的设计思想。(比如租房子。以前租房子需要一个房子一个房子找,费时费力,然后现在加入一个房屋中介,把你需要的房型告诉中介,就可以直接选到需要的房子,中介就相当于spring容器。)
    2)AOP(面向切面)
    是面向对象开发的一种补充,它允许开发人员在不改变原来模型的基础上动态的修改模型以满足新的需求,如:动态的增加日志、安全或异常处理等。AOP使业务逻辑各部分间的耦合度降低,提高程序可重用性,提高开发效率。

    1.横切关注点:从每个方法中抽取出来的同一类非核心业务代码。
    2.切面:封装横切信息点的类,每个关注点体现为一个通知方法。
    3.通知:切面必须要完成的各个具体工作,也就是切面里的一个个方法。
    4.目标:被通知的对象,也就是被通知方法所作用的对象。
    5.代理:像目标对象应用通知之后所创建的代理对象。
    6.连接点:横切关注点在程序代码中的具体体现,对应用程序执行的某个特定位置。(通俗来讲就是一个个的方法)
    7.切入点:切入点就是定位连接点的方式。每个通知上的切入点表达式找到对应的连接点,执行通知之后连接点也就变成了切入点。
    在这里插入图片描述

    2.Spring MVC

    <复杂版>
    1、 用户发送请求至前端控制器DispatcherServlet。
    2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
    3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
    4、 DispatcherServlet调用HandlerAdapter处理器适配器。
    5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
    6、 Controller执行完成返回ModelAndView。
    7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
    8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
    9、 ViewReslover解析后返回具体View。
    10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
    11、 DispatcherServlet响应用户。

    <简单版>
    1.客户端发送请求到DispacherServlet(分发器)
    2.由DispacherServlet控制器查询HanderMapping,找到处理请求的Controller
    3.Controller调用业务逻辑处理后,返回ModelAndView
    4.DispacherSerclet查询视图解析器,找到ModelAndView指定的视图
    5.视图负责将结果显示到客户端
    在这里插入图片描述

    3.Mybatis (核心是SqlSession)

    mybatis是对jdbc的封装,它让数据库底层操作变的透明。mybatis的操作都是围绕一个sqlSessionFactory实例展开的。mybatis通过配置文件关联到各实体类的Mapper文件,Mapper文件中配置了每个类对数据库所需进行的sql语句映射。在每次与数据库交互时,通过sqlSessionFactory拿到一个sqlSession,再执行sql命令。

    二、代码实战

    1.创建配置工程

    1)创建maven工程
    2)创建目录

    • src——main下创建两个文件夹(Java和resources)。
    • 和main同级的创建一个test,test里面创建一个Java。
    • 在这里插入图片描述

    3)配置工程

    • file——project structure——modules
    • 在这里插入图片描述
      4)创建包
    • 在src——java下创建问价夹(XXX),
    • (XXX)下创建entity,mapper,,service和util包。

    5)配置依赖
    pom.xml加入依赖,一个是Mybatis的,一个是MySQL的。

    代码如下(示例):

        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>3.5.1</version>
        </dependency>
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.36</version>
        </dependency>
    

    在这里插入图片描述

    2.代码实战(查询记录数)

    1)设计数据库
    在这里插入图片描述
    1)创建实体类
    在entity下new一个名为person的class

    代码如下(示例):

    public class Person {
        private Integer Id;
        private String name;
        private String nickname;
        private Integer age;
    
        public Integer getId() {
            return Id;
        }
    
        public void setId(Integer id) {
            this.Id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getNickname() {
            return nickname;
        }
    
        public void setNickname(String nickname) {
            this.nickname = nickname;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "Id=" + Id +
                    ", name='" + name + '\'' +
                    ", nickname='" + nickname + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    

    2)Mapper接口
    定义方法(实体名+Mapper)
    在mapper下创建一个名为PersonMapper的interface

    public interface PersonMapper {
        //定义查询记录方法数
        public Integer findCount();
        }
    

    3)resources包

    • resources包下创建cn包
    • cn包下创建kgc包
    • kgc包下创建一个XML(这里的xml文件名与mapper接口名一致)
      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">
    
    //查询映射标签(select):
    <mapper namespace="cn.kgc.mapper.PersonMapper">
        <select id="findCount" resultType="java.lang.Integer">
        </select>
    </mapper>
    

    (1)mapper叫根节点,根节点有个属性是namespace=""、namespace=""、的作用是映射我们mapper的全路径,在以后的使用中会自动映射成我们mapper的实现类
    (2)select里面的Id=“”一般和我们PersonMapper里面的方法名保持一致
    (3)返回值这里有一个专门的属性叫resultType="java.lang.Integer"
    (4)方法名和返回值都对应之后看有无参数,如果有要加上parameterType=""

    4)写sql语句`

    <mapper namespace="cn.kgc.mapper.PersonMapper">
        <select id="findCount" resultType="java.lang.Integer">
            select count(*) from t_user
        </select>
    </mapper>
    

    5)配置主配置文件mybatis-config.xml`
    在resources里新建mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
            PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
            "http://ibatis.apache.org/dtd/ibatis-3-config.dtd">
    
    //根节点:爷爷
    <configuration>
           //子节点:爸爸
        <environments default="development">
        //爸爸天生有很多的孙子(这里可以配置很多个数据库,比如development1,development2等等)
         <environment id="development">
          <transactionManager type="JDBC" /> </transactionManager>//事务里面有一个类型type,可以配JDBC(JDBC利用的机制是数据库它的一个数据源的一个事务JDBC。可以允许不用数据库的事务)
          <dataSource type="POOLED"></dataSource>//(dataSource属性,代表数据源,链接数据库。“POOLED”这里的连接池根据需要可以更改。)
         </environment>
         //development2(一般企业里配一个开发环境,一个测试环境)
          //    <environment id="development2">
        //  <transactionManager type="" /> </transactionManager>
        //  <dataSource type=""></dataSource>
       //  </environment>
      //  </environments>
    </configuration>
    
    mybatis-config.xml完整代码:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
            PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
            "http://ibatis.apache.org/dtd/ibatis-3-config.dtd">
    
    <configuration>
        <!--jdbc.properties配置文件-->
        <properties resource="jdbc.properties"></properties>
        <!--setttings:控制mybatis全局配置行为-->
        <settings>
            <!--设置mybatis输出日志-->
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
        <!--环境配置:数据库的连接信息-->
        <!--default:中配置的值需要和某个environment配置的id相同,
            通知mybatis使用具体哪一个数据库的连接信息,即具体访问对应的数据库-->
        <environments default="development">
            <!--environment:一个数据库信息的配置,环境-->
            <!--id属性:一个唯一值,自定义,表示环境的名称-->
            <environment id="development">
                <!--transactionManager属性:mybatis的事务类型-->
                <transactionManager type="JDBC" />
                <!--dataSoure属性:代表数据源,连接数据库-->
                <!--type属性:JDBC 表示使用的是使用连接池的数据源-->
                <dataSource type="POOLED">
                    <!--配置驱动-->
                    <property name="driver" value="${driver}"/>
                    <!--配置连接数据库的url字符串-->
                    <property name="url" value="${url}"/>
                    <!--配置连接数据库的用户名-->
                    <property name="username" value="${username}"/>
                    <!--配置连接数据库的密码-->
                    <property name="password" value="${password}"/>
                </dataSource>
            </environment>
        </environments>
        <!--sql映射文件标签-->
        <mappers>
            <!--reource:从类路径开始的路径信息:target/clasess(类路径)-->
            <mapper resource="cn/kgc/mapper/PersonMapper.xml"/>
        </mappers>
    </configuration>
    

    5)测试`
    在test——Java包下新建一个名为TestMybatis的测试类
    测试用例怎么写:测一个对象sqlSession,需要通过sqlSessionFactor()对象才能创建sqlSession。sqlSessionFactor()需要通过sqlSessionFactor()Builder()来创建出来。

    在这里插入图片描述

    1. 先new一个SqlSessionFactoryBuilder(),得到一个返回值builder
     SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    
    1. 获取我们的SqlSessionFactory,要用builder.上我们的builder()方法,通过流的形式传一个In的参数。
    2. 通过Resources.getResourceAsStream(“”)读取我们的主配置文件才能调用我们的依赖信息,在这里抛异常。这里有一个返回值nputStream in(字节流),通过字节流就可以读取
    3. 这时builder.build(in);得到哟个返回值就是SqlSessionFactory factory。
    4. 得到SqlSessionFactory factory之后,根据图片的流程就要得到我们的SqlSession。
    5. factory.openSession()打开我们的Session,就可以得到我们的Session
    6. 执行sql语句。sqlSession.getMapper(这里的mapper利用的是我们的一个反射机制,机制利用的时我们的一个接口)通过sqlSession.getMapper(PersonMapper.class)调用一个调用方法,得到一个返回值count
    7. 输出对应的返回值
    8. 关闭sqlsession
    public class TestMybatis {
        @Test
        public void testHelloWorld() throws IOException {
            //1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            //2.实例化SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.调用builder对象的builder()方法,获取SqlSessionFactory对象
            SqlSessionFactory factory = builder.build(in);
            //4.调用factory对象的openSession()方法,获取SqlSession对象
            SqlSession sqlSession = factory.openSession();
            //5.调用接口的方法
            Integer count = sqlSession.getMapper(PersonMapper.class).findCount();
            //6.输出对应的返回值count
            System.out.println("count:" + count);
            //7.关闭 SqlSession
            sqlSession.close();
        }
     }
    

    3.代码实战(增加)

    PersionMapper

    public interface PersonMapper {
        //定义查询记录方法数
        public Integer findCount();
        //增加
        public Integer addPerson(Person person);
        }
    

    PersonMapper.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">
    <mapper namespace="cn.kgc.mapper.PersonMapper">
        <select id="findCount" resultType="java.lang.Integer">
            select count(*) from t_user
        </select>
        <insert id="addPerson" parameterType="cn.kgc.entity.Person">
            insert into t_user(name,nickname,age) values(#{name},#{nickname},#{age})
        </insert>
        </mapper>
    

    测试类

        @Test
        public void testInsert() throws Exception {
            //1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            //2.实例化SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.调用builder对象的builder()方法,获取SqlSessionFactory对象
            SqlSessionFactory factory = builder.build(in);
            //4.调用factory对象的openSession()方法,获取SqlSession对象
            SqlSession sqlSession = factory.openSession();
            //5.调用接口的方法
            Person p = new Person();
            p.setName("李四");
            p.setNickname("一个人的夜晚上");
            p.setAge(22);
            sqlSession.getMapper(PersonMapper.class).addPerson(p);
            //6.提交实物,该行代码必须放在关闭sqlsession之前
            sqlSession.commit();
            sqlSession.close();
        }
    

    3.代码实战(增删改查,模糊精确查询集合)

    完整工程代码
    Person类

    package cn.kgc.entity;
    
    public class Person {
        private Integer Id;
        private String name;
        private String nickname;
        private Integer age;
    
        public Integer getId() {
            return Id;
        }
    
        public void setId(Integer id) {
            this.Id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getNickname() {
            return nickname;
        }
    
        public void setNickname(String nickname) {
            this.nickname = nickname;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "Id=" + Id +
                    ", name='" + name + '\'' +
                    ", nickname='" + nickname + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    
    

    PersonMapper类

    package cn.kgc.mapper;
    
    import cn.kgc.entity.Person;
    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    
    public interface PersonMapper {
        //定义查询记录方法数
        public Integer findCount();
        //增加
        public Integer addPerson(Person person);
        //修改功能
        public Integer updatePerson(Person person);
        //删除功能
        public Integer delById(Integer Id);
        //删除功能2
        public Integer delById2(Person person);
        //查询对象
        public Person findById(Integer Id);
        //查询集合
        public List<Person> findAll();
        //模糊查询
        public List<Person> findByName(String name);
        //通过用户名和昵称 绝对查询
        public List<Person> findByPerson(Person person);
        //通过用户名和昵称 绝对查询2
        public List<Person> findByPerson2(@Param("name")String name,@Param("nickname")String nickname);
        //测试¥(不安全)符号和#(安全)的作用
        public List<Person> findColList(@Param("colname")String colname);
    }
    
    

    MybatisUtil类

    package cn.kgc.util;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class MytabisUtil {
        private static SqlSessionFactory factory = null;
    
        static {
            try {
                InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
                SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
                factory = builder.build(in);
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        //获取SqlSession对象
        public static SqlSession getSqlSession(){
            SqlSession sqlSession = null;
            if(factory!=null){
                sqlSession = factory.openSession();
            }
            return sqlSession;
        }
    }
    
    

    PersonMapper.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">
    <mapper namespace="cn.kgc.mapper.PersonMapper">
        <select id="findCount" resultType="java.lang.Integer">
            select count(*) from t_user
        </select>
        <insert id="addPerson" parameterType="cn.kgc.entity.Person">
            insert into t_user(name,nickname,age) values(#{name},#{nickname},#{age})
        </insert>
        <update id="updatePerson" parameterType="cn.kgc.entity.Person">
            update t_user set name=#{name},nickname=#{nickname},age=#{age} where Id = #{Id}
        </update>
        <delete id="delById" parameterType="cn.kgc.entity.Person" >
            delete from t_user where id = #{Id}
        </delete>
        <delete id="delById2" parameterType="cn.kgc.entity.Person">
            delete from t_user where id = #{Id}
        </delete>
        <select id="findById" resultType="cn.kgc.entity.Person" parameterType="java.lang.Integer">
            select * from t_user where id = #{Id}
        </select>
        <select id="findAll" resultType="cn.kgc.entity.Person">
            select * from t_user
        </select>
        <select id="findByName" resultType="cn.kgc.entity.Person" parameterType="java.lang.String">
            select * from t_user where `name` like concat('%',#{name},'%')
        </select>
        <select id="findByPerson" parameterType="cn.kgc.entity.Person" resultType="cn.kgc.entity.Person">
            select * from t_user where  `name` = #{name} and nickname = #{nickname}
        </select>
        <select id="findByPerson2" parameterType="cn.kgc.entity.Person" resultType="cn.kgc.entity.Person">
            select * from t_user where  `name` = #{name} and nickname = #{nickname}
        </select>
        <select id="findColList" resultType="cn.kgc.entity.Person">
             select * from t_user order by ${colname}
        </select>
    </mapper>
    

    jdbc.properties(配置文件)

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/db_202125
    username=root
    password=123
    

    mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
            PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
            "http://ibatis.apache.org/dtd/ibatis-3-config.dtd">
    
    <configuration>
        <!--jdbc.properties配置文件-->
        <properties resource="jdbc.properties"></properties>
        <!--setttings:控制mybatis全局配置行为-->
        <settings>
            <!--设置mybatis输出日志-->
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
        <!--环境配置:数据库的连接信息-->
        <!--default:中配置的值需要和某个environment配置的id相同,
            通知mybatis使用具体哪一个数据库的连接信息,即具体访问对应的数据库-->
        <environments default="development">
            <!--environment:一个数据库信息的配置,环境-->
            <!--id属性:一个唯一值,自定义,表示环境的名称-->
            <environment id="development">
                <!--transactionManager属性:mybatis的事务类型-->
                <transactionManager type="JDBC" />
                <!--dataSoure属性:代表数据源,连接数据库-->
                <!--type属性:JDBC 表示使用的是使用连接池的数据源-->
                <dataSource type="POOLED">
                    <!--配置驱动-->
                    <property name="driver" value="${driver}"/>
                    <!--配置连接数据库的url字符串-->
                    <property name="url" value="${url}"/>
                    <!--配置连接数据库的用户名-->
                    <property name="username" value="${username}"/>
                    <!--配置连接数据库的密码-->
                    <property name="password" value="${password}"/>
                </dataSource>
            </environment>
        </environments>
        <!--sql映射文件标签-->
        <mappers>
            <!--reource:从类路径开始的路径信息:target/clasess(类路径)-->
            <mapper resource="cn/kgc/mapper/PersonMapper.xml"/>
        </mappers>
    </configuration>
    

    TestMybatis类

    import cn.kgc.entity.Person;
    import cn.kgc.mapper.PersonMapper;
    import cn.kgc.util.MytabisUtil;
    import jdk.internal.util.xml.impl.Input;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.Test;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    
    
    public class TestMybatis {
        @Test
        public void testHelloWorld() throws IOException {
            //1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            //2.实例化SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.调用builder对象的builder()方法,获取SqlSessionFactory对象
            SqlSessionFactory factory = builder.build(in);
            //4.调用factory对象的openSession()方法,获取SqlSession对象
            SqlSession sqlSession = factory.openSession();
            //5.调用接口的方法
            Integer count = sqlSession.getMapper(PersonMapper.class).findCount();
            //6.输出对应的返回值count
            System.out.println("count:" + count);
            //7.关闭 SqlSession
            sqlSession.close();
        }
    
        @Test
        public void testInsert() throws Exception {
            //1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            //2.实例化SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.调用builder对象的builder()方法,获取SqlSessionFactory对象
            SqlSessionFactory factory = builder.build(in);
            //4.调用factory对象的openSession()方法,获取SqlSession对象
            SqlSession sqlSession = factory.openSession();
            //5.调用接口的方法
            Person p = new Person();
            p.setName("李四");
            p.setNickname("一个人的夜晚上");
            p.setAge(22);
            sqlSession.getMapper(PersonMapper.class).addPerson(p);
            //6.提交实物,该行代码必须放在关闭sqlsession之前
            sqlSession.commit();
            sqlSession.close();
        }
    
        @Test
        public void testupdate() throws Exception {
            //1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            //2.实例化SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.调用builder对象的builder()方法,获取SqlSessionFactory对象
            SqlSessionFactory factory = builder.build(in);
            //4.调用factory对象的openSession()方法,获取SqlSession对象
            SqlSession sqlSession = factory.openSession();
            Person p2 = new Person();
            p2.setId(2);
            p2.setName("赵四");
            p2.setNickname("来啊,造作啊");
            p2.setAge(23);
            sqlSession.getMapper(PersonMapper.class).updatePerson(p2);
            //6.提交实物,该行代码必须放在关闭sqlsession之前
            sqlSession.commit();
            sqlSession.close();
        }
        @Test
        public void testdel() throws  Exception{
            //1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            //2.实例化SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.调用builder对象的builder()方法,获取SqlSessionFactory对象
            SqlSessionFactory factory = builder.build(in);
            //4.调用factory对象的openSession()方法,获取SqlSession对象
            SqlSession sqlSession = factory.openSession();
            sqlSession.getMapper(PersonMapper.class).delById(2);
            sqlSession.commit();
            sqlSession.close();
        }
        @Test
        public void testdel2 () throws Exception{
            //1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            //2.实例化SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.调用builder对象的builder()方法,获取SqlSessionFactory对象
            SqlSessionFactory factory = builder.build(in);
            //4.调用factory对象的openSession()方法,获取SqlSession对象
            SqlSession sqlSession = factory.openSession();
            Person person = new Person();
            person.setId(2);
            sqlSession.getMapper(PersonMapper.class).delById2(person);
            sqlSession.commit();
            sqlSession.close();
        }
        @Test
        public void testfindById () throws Exception{
            //1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            //2.实例化SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.调用builder对象的builder()方法,获取SqlSessionFactory对象
            SqlSessionFactory factory = builder.build(in);
            //4.调用factory对象的openSession()方法,获取SqlSession对象
            SqlSession sqlSession = factory.openSession();
    
            Person person = sqlSession.getMapper(PersonMapper.class).findById(1);
            System.out.println("id"+ person.getId()+"name"+ person.getName()+"nickname"+ person.getNickname()+"age"+ person.getAge());
            sqlSession.close();
        }
        @Test
        public void testfindAll () throws IOException{
           String str ="mybatis-config.xml";
            InputStream in =Resources.getResourceAsStream(str);
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory factory = builder.build(in);
            SqlSession sqlSession = factory.openSession();
    
            List<Person> all = sqlSession.getMapper(PersonMapper.class).findAll();
            for(Person p:all){
                System.out.println(p);
            }
            sqlSession.close();
        }
        @Test
        public void testfindByName () throws IOException{
            String str ="mybatis-config.xml";
            InputStream in =Resources.getResourceAsStream(str);
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory factory = builder.build(in);
            SqlSession sqlSession = factory.openSession();
    
            List<Person> list = sqlSession.getMapper(PersonMapper.class).findByName("wqz");
            for(Person p:list){
                System.out.println(p);
            }
            sqlSession.close();
        }
        @Test
        public void testfindByPerson () throws IOException{
            String str ="mybatis-config.xml";
            InputStream in =Resources.getResourceAsStream(str);
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory factory = builder.build(in);
            SqlSession sqlSession = factory.openSession();
            Person person = new Person();
            List<Person> list = sqlSession.getMapper(PersonMapper.class).findByPerson(person);
            for(Person p:list){
                System.out.println(p);
            }
            sqlSession.close();
        }
        @Test
        public void findByPerson2 () throws Exception {
            //1.通过流的机制获取主配置文件mybatis-config.xml的主要配置信息
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            //2.实例化SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.调用builder对象的builder()方法,获取SqlSessionFactory对象
            SqlSessionFactory factory = builder.build(in);
            //4.调用factory对象的openSession()方法,获取SqlSession对象
            SqlSession sqlSession = factory.openSession();
            String name = "王五";
            String nickname = "123";
            List<Person> list = sqlSession.getMapper(PersonMapper.class).findByPerson2(name,nickname);
            for(Person p:list){
                System.out.println("name:"+p.getName()+"nickname"+p.getNickname());
            }
            sqlSession.close();
        }
        @Test
        public void testfindCount(){
            SqlSession sqlSession = MytabisUtil.getSqlSession();
            Integer count = sqlSession.getMapper(PersonMapper.class).findCount();
            System.out.println(count);
        }
    
        @Test
        public void findColList(){
            SqlSession sqlSession = MytabisUtil.getSqlSession();
            List<Person> colList = sqlSession.getMapper(PersonMapper.class).findColList("Id");
            for (Person p:colList){
                System.out.println(p);
    
    
            }
        }
    }
    
    

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!--
      Licensed to the Apache Software Foundation (ASF) under one
      or more contributor license agreements.  See the NOTICE file
      distributed with this work for additional information
      regarding copyright ownership.  The ASF licenses this file
      to you under the Apache License, Version 2.0 (the
      "License"); you may not use this file except in compliance
      with the License.  You may obtain a copy of the License at
    
       http://www.apache.org/licenses/LICENSE-2.0
    
      Unless required by applicable law or agreed to in writing,
      software distributed under the License is distributed on an
      "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
      KIND, either express or implied.  See the License for the
      specific language governing permissions and limitations
      under the License.
    -->
    <!-- $Id: pom.xml 642118 2008-03-28 08:04:16Z reinhard $ -->
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    
      <modelVersion>4.0.0</modelVersion>
      <packaging>war</packaging>
    
      <name>20211125</name>
      <groupId>org.example</groupId>
      <artifactId>20211125</artifactId>
      <version>1.0-SNAPSHOT</version>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>maven-jetty-plugin</artifactId>
            <version>6.1.7</version>
            <configuration>
              <connectors>
                <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
                  <port>8888</port>
                  <maxIdleTime>30000</maxIdleTime>
                </connector>
              </connectors>
              <webAppSourceDirectory>${project.build.directory}/${pom.artifactId}-${pom.version}</webAppSourceDirectory>
              <contextPath>/</contextPath>
            </configuration>
          </plugin>
        </plugins>
      </build>
    
      <dependencies>
        <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>3.5.1</version>
        </dependency>
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.36</version>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
        </dependency>
        <!--dependency>
          <groupId>org.example</groupId>
          <artifactId>[the artifact id of the block to be mounted]</artifactId>
          <version>1.0-SNAPSHOT</version>
        </dependency-->
      </dependencies>
    
    </project>
    
    
    展开全文
  • 现在来解释一下有关的意义: 1:width="300"(边框的宽度;300为象素值。可根据文字的多少自由调整,一般不超过760) 2:height="400"(边框的高度;400为象素值。可根据文字的多少自由调整。) 3:border="10"(外...
  • Tmux允许用户在终端中的程序之间切换,添加屏幕窗格,并将多个终端连接到一个会话,使其保持同步。在远程服务器上工作时,Tmux特别有用,允许用户创建新的选项卡而无需再次登录。 六、du du命令用于生成关于文件和...
  • 我们可以这样看,new ……()是构造方法,调用来构造一个匿名对象,其后的{}不是Java的特殊语法,但是Java中可以将方法定义在里面(这里的方法生命周期与匿名对象相 ),当然,此处是用于实现接口的方法。...
  • 官方解释格式如下: {componentType:'series',// 系列类型seriesType:string,// 系列在传入的 option.series 中的 indexseriesIndex:number,// 系列名称seriesName:string,// 数据名,类目名name:string,// 数据在...
  • 移动端SEO优化需要注意的事情:一、选择合适的方式布局移动端,并表达与pc端对应关系1,单一域名下请使用一种配置方式(跳转适配、代码适配、自适应),例如,不要把移动站的页面作为pc站网址中的一个子目录来配置...
  • 对于生成的锚,计算得到任意一个锚与所有的边界的iou后,如何将真实边界分配给锚呢(也就是每一个锚对应哪一个真实的边界呢,或者对应背景呢),以下《动手学》写的真好,建议反复阅读。 关于torch....
  • Java Spring 框架详解

    千次阅读 2021-01-11 18:18:02
    下面通过实际生活中的一个例子来解释 IoC 和 DI 。 当人们需要一件东西时,第一反应就是找东西,例如吃面包。在没有面包店和有面包店两种情况下,您会怎么做?在没有面包店时,最直观的做法可能是您按照自己的口味...
  • Qt边框border概述

    千次阅读 2021-04-28 21:47:52
    每个边框有3个方面:样式(或外观)、颜色、以及其宽度(粗细),下面我们分别重点解释这三项。 边框样式(border-style) 设置元素所有边框的样式,或者单独地为各边设置边框样式。它有10个属性值,分别是: none:...
  • 一文详解什么是可解释AI

    千次阅读 多人点赞 2021-03-03 11:43:08
    摘要:本文带来什么是可解释AI,如何使用可解释AI能力来更好理解图片分类模型的预测结果,获取作为分类预测依据的关键特征区域,从而判断得到分类结果的合理性和正确性,加速模型调优。 1. 为什么需要可解释AI? ...
  • 需求:页面中的单选需要有这样的效果。 1、单选按钮组是保持原有的只可以选中一个单选按钮。 2、如果一个单选按钮是选中状态,当再次点击这个单选按钮时,选中状态就会取消。 代码: html: <el-radio-group ...
  • html自定义提示

    2021-06-27 12:20:55
    自定义html提示比较令人困惑的就是编写三角形的样式;以前的实现方式是在标签...下面是本人的一个简单例子:提示的三角形原理#tips {display: inline-block;position: relative;padding: 0px 15px;border-radiu...
  • 礼乐之情,故明王以相沿万石君名奋,其父赵人也,姓石氏。赵亡,徙居温。高祖东击项籍,过河内,时奋年十五,为小吏,侍高祖。高祖与语,爱其恭敬,问曰:“若何有?”对曰:“奋独有母,不幸失明。家贫。有姊,能...
  • 通过本酒店客房管理系统,酒店的决策者可以直接管理和运营相关的业务,有效地发现和挖掘前景,及时与自己的上级、下属、行业单位进行的沟通与交流,同心协作,积极为酒店事业的发展与决策贡献力量。使酒店管理适应...
  • Activiti7   工作流(Workflow),就是通过计算机对业务流程自动化执行管理。它主要解决的是“使在多个参与者之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个预期的业务目标,或者促使此...
  • 第一个问题是,这些疾病是由多个不同的放射科医生标记的,对于一种异常可能有多个不同的边界。所以我们必须过滤这些(或者在本例中“融合”它们),以避免混淆我们的模型。 第二个问题是一些密集疾病区域包含多个...
  • 深度学习的可解释性!

    千次阅读 2021-02-12 22:00:00
    一、深度学习的可解释性研究概述随着深度学习模型在人们日常生活中的许多场景下扮演着越来越重要的角色,模型的「可解释性」成为了决定用户是否能够「信任」这些模型的关键因素(尤其是当我们需要机器为...
  • Java安全框架---JWT详解

    2020-12-24 10:41:12
    JWT官网解释2. JWT作用3. 传统的Session认证1. 认证方式2. 认证流程3. 暴露问题4. JWT认证1. 认证流程2. JWT优点5.JWT的结构是什么?1. 令牌组成2. Header3. Payload4.Signature二 . JWT案列使用1. pom.xml 导入依赖...
  • Fluttee框架介绍 Flutter基础

    千次阅读 2021-12-03 15:23:10
    渲染树在上屏前会生成一棵 Layer 树,这里不做过多解释。 树更新 全局更新:调用runApp(rootWidget),一般flutter启动时调用后不会再调用 局部子树更新:将子树作StatefulWidget的一个子Widget,并创建对应的State...
  • api 'com.github.bumptech.glide:glide:4.11.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' 点击Sync进行同步依赖一下,这里你如果看到api觉得很奇怪的话,我这里解释一下,它和...
  • Python+Pytest+tox 接口自动化测试框架

    千次阅读 多人点赞 2021-02-02 18:28:45
    “envlist”字段定义了tox操作的环境 2)[testenv]下面是虚拟环境默认配置项: “basepython”配置的是python解释器版本; “setenv”设置环境变量,在项目中可以读取环境变量,从而决定运行哪个环境的配置 3)取...
  • 介绍: spring,springmvc,mybatis,mysql,eclipse 效果图: 数据库表: CREATE TABLE IF NOT EXISTS admin ( id mediumint(9) NOT NULL AUTO_INCREMENT, username varchar(30) NOT NULL, ...
  • 这里说的普通对象我做个解释,表达的意思就是XLog不能直接格式化对的对象都看作普通对象,json、xml、Bundle和集合之外的对象,大概这么个意思,不要太纠结!好了,继续~ 怎么样?!上面几种打印方式是不是很nice,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 269,053
精华内容 107,621
关键字:

同框的解释