Mybatis之旅(序)

作者: 宫本花藏 | 来源:发表于2020-02-26 22:41 被阅读0次

    序中序

        本系列旨在探讨mybatis底层逻辑,顺便以源码出发,探究Java语言的若干机制。

        同时,此系列采取工程代码开发中敏捷的原则,不会像以往一样动辄写数千字,而是以“小步快跑”的形式,快速对自己所学的知识作出反应,总结、分享出来。

        本文的第一、二节讲述一些网页应用,ORM和持久化的基本概念,第三节会讲一个最简单的mybatis使用的实例(正如网上大部分博客那样)。

    一、网页应用

        以简书一个不知名博主的主页为例:https://www.jianshu.com/u/6d6837a8715a

        当我们在浏览器输入上面这个链接,按下回车的时候,浏览器就会根据这个链接向相关的服务器请求数据(详情可见《无线世界》系列)。服务器会返回html,js和css文件给我们的电脑,我们电脑上的浏览器会解析这些文件,并且将简书的页面展示给我们看。

        这种模式被成为浏览器/服务器模式(B/S Browser/Server)。另外一种常见的叫做客户端/服务器模式(C/S Client/Server),咱也不懂,咱也不去说。

        但是简书上的博主、用户这么多,简书不可能为每一个人都单独建立一套html/js/css文件,于是采取了比较讨巧的做法:只用一份html/js/css文件来用作页面的展示,而将用户名,文章,动态等信息存进数据库中,为每一个用户配置一个唯一id,用这个id来关联用户的数据。

        这就可以引申到MVC(Model-View-Control)模型的基本思想。M指业务模型,V指用户界面,C指控制器(用于业务模型和用户界面的同步等)。控制器处理用户的入参(比如上例中简书链接最后的id),控制器会根据入参到业务模型中存取数据(上例中就是取出用户“宫本花藏”的文章、评论等信息),最后在用户界面上予以展示(如上上图所示)。

    二、持久化框架与ORM

        在面向对象中,有三层架构的思想。对于服务器来说,用户能够接触到的往往是最外的表现层,使用MVC模式来接收用户数据,或者向用户展示数据;服务层用户用户数据的逻辑处理;而最里面的持久层用于和数据库打交道,负责数据的增删改查。

        人们都说mybatis是持久层框架,就是说mybatis这个框架,是专门用来让Java程序和数据库交互的。

        如果说谁发明了一个服务层框架,就是说他设计的这个框架是专门用来处理业务逻辑的。emmm思考题:这么说来,那些算法的jar包看来都能算成服务层框架了???

        众所周知,服务器能正常运行是要靠代码部署在上面的。Java是常用的服务器逻辑代码。如果想要通过Java访问数据库,就必须使用到Java中的JDBC接口。传统的JDBC连接数据库方式很繁琐,要先注册数据库驱动类,确认url,账号密码,再通过DriverManager打开数据库连接,将拼接好的SQL语句以字符串的形式给Statement,得到执行结果后手动关闭数据库链接。

        为了解决该问题,ORM(Object Relation Mapping,对象-关系映射)框架应运而生。java代码可以根据映射配置文件,完成数据在对象模型(Java语言)与关系模型(SQL语言)之间的映射(比如java中的String类可以转换成SQL中的VARCHAR数据类型)。

        另外,频繁的新建、关闭数据库连接会极大的消耗资源,成为系统的性能瓶颈。ORM框架的另外一个特色功能就是建立数据库连接池:专门创建若干给数据库连接,当某进程有连接请求时就将连接分配给该进程,用完了也不释放连接,而是将连接对象再放进池子里面来,供别的进程使用。

        在书写代码的过程中,千千万万的程序员上演着可歌可泣的与bug斗智斗勇的故事,闻者流泪,听者伤心。代码既要处理用户输入,又要执行业务逻辑,存取数据;同时内要考虑负载均衡进程冲突资源抢占,外要预防非法输入网络攻击安全漏洞,忙不胜收。

        于是,伟大的程序员先贤们针对代码混乱的问题,建立了各种框架。这些框架划分不同功能的代码,让它们各司其职。这些代码大多可以不依赖其他服务独立运行,并且提供某些特定服务。随着时代的发展,不同功能的代码还会划分层次,分出哪些用于公共服务,哪些用于应用实现。

        比如上面这个,分成了基础支持层,核心处理层和接口层3层。每一层各个模块的功能目的都不相同。这个框架就是mybatis整体的框架,也是接下来我们的探索旅程的全景图。

        不过由于本文是序文,所以本文只是给了一个最简单的mybatis使用的示例。

    三、mybatis示例

        所需:mysql数据库,集成开发环境IDEA(社区版即可),maven,预先装好的JDK1.8,一个能联网的环境

    3.1 MySQL

        既然mybatis是与数据库打交道的框架,就必须安装数据库。以免费的mysql为例,需要先注册ORACLE账户,登录进行下载。没有ORACLE账户的需要注册一个,是免费的。

        mysql向导链接:https://www.mysql.com/cn/why-mysql/white-papers/visual-guide-to-installing-mysql-windows-zh/

        安装的时候需要配置用户名和密码,按它给的pdf文档来即可。安装完成后,打开的界面如下所示:

        点击 Local instance 字样的方框,就可以进入到页面中

        进入数据库后,需要先创建schema。schema可以理解为是一个用户,一个用户可以拥有多张数据表。不同用户之间的数据表不同,并且有访问权限控制。输入以下语句创建用户:

        create schema sjjdata default character set utf8 collate utf8_general_ci;

        选择该用户,创建一个包含id,姓名,年龄3个字段的表,表的名字叫做student(是不是很俗)

    use sjjdata;

        create table student

        (id int(11),

        name varchar(25),

        age int(11));

        最终我们在mysql数据库中,创建了一个名为sjjdata的用户,在这个用户下新建了一张名为student的表。

    3.2 Maven

        程序语言发展至今,我们编程的时候再也不可能从零开始写。我们会依靠前人的编程成果,即调用代码库的形式,提升我们的编程效率。在Java中,我们通常以使用jar包的形式,调用前人写好的方法,而忽略实现该方法的细节(这种行为也被成为引用依赖)。jar包是一群java文件和配置文件的集合。除了jar包以外,随着规模的不同,还有tar包,war包。一个jar包举例:

        发布jar包的团队或个人通常会每隔一段时间更新这个包, 修复一些bug或者新增一些功能。为了便于区分,他们为每一次发布的jar包取了一个版本号,比如上图中的mybatis包的版本是3.2.7。

        其他程序员在编写程序引用jar包的时候,常常因为jar包的版本不对而引发bug。为了解决此类问题,有很多专门解决依赖的工具,maven就是其中一个。它通过xml文件(往往这个文件的名字叫做pom.xml)确定具体引用哪个版本的哪个包,就可以从它的maven仓库中取出此包,供程序员调用。这么做的好处是在程序移植的时候,只要把对应的xml文件也移植过去,其他机器上就算没有这个jar包,或者没有特定版本的jar包,也可以通过xml文件到maven仓库中找到它。

        maven是apache的开源项目,可以在官网下载。https://maven.apache.org

        下载过来的是一个zip文件,解压,随便放在某个目录就可以。为了避免不必要的字符编码问题,建议放在英文路径下。

        当然,有时候IDEA自己在安装的时候可能已经自带了maven了……

    3.3 Java

        IDEA也有官网,也有免费使用的版本,奉上链接:

    https://www.jetbrains.com/products.html#type=ide

        笔者下载的是2019.3版本,打开界面如下所示:

        进入后,点击file-->new-->project,选择maven

      点击next,确定工程名,直接finish

        在工程的出生地,就可以发现布局的很有规律的目录,以及一个pom.xml文件,这些都是maven规范自动生成的。

        在xml文件中,贴入如下代码。其含义将在之后逐渐解释。

    <?xml version="1.0"encoding="UTF-8"?>

    <projectxmlns="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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>

    <artifactId>SecondMybatis</artifactId>

    <version>1.0-SNAPSHOT</version>

    <dependencies>

    <dependency>

    <groupId>org.mybatis</groupId>

    <artifactId>mybatis</artifactId>

    <version>3.2.7</version>

    </dependency>

    <dependency>

    <groupId>mysql</groupId>

    <artifactId>mysql-connector-java</artifactId>

    <version>5.1.47</version>

    </dependency>

    <dependency>

    <groupId>junit</groupId>

    <artifactId>junit</artifactId>

    <version>4.12</version>

    <!-- <scope>test</scope>-->

    </dependency>

    <dependency>

    <groupId>org.apache.logging.log4j</groupId>

    <artifactId>log4j-api</artifactId>

    <version>2.11.1</version>

    </dependency>

    <dependency>

    <groupId>org.apache.logging.log4j</groupId>

    <artifactId>log4j-core</artifactId>

    <version>2.11.1</version>

    </dependency>

    </dependencies>

    </project>   

        复制完之后,程序右下角会弹出这样的对话框:

         点击Import Changes,就可以加载pom.xml指定的jar包

        按照如下格式建立目录(直接右键文件夹,new,选择java或者package,这里不再赘述):

      在UserBeanMapper中,写入如下代码:

    package com.sjj.dao;

    import com.sjj.entity.UserBeanVO;

    import java.util.List;

    public interface UserBeanMapper {

    UserBeanVO queryUserByName(String name);

    List<UserBeanVO> queryAll();

    int insertUser(UserBeanVO userBean);

    int deleteUserByName(String name);

    int updateUserById(UserBeanVO userBean,int id);

    }

      在UserBeanVO中,写入如下代码:

    package com.sjj.entity;

    /**

    * @author jun

    * @date 2019/1/31

    */

    public class UserBeanVO {

    private int id;

    private String name;

    private int age;

    public int getId() {

    return id;

    }

    public void setId(int id) {

    this.id = id;

    }

    public String getName() {

    return name;

    }

    public void setName(String name) {

    this.name = name;

    }

    public int getAge() {

    return age;

    }

    public void setAge(int age) {

    this.age = age;

    }

    @Override

    public String toString() {

    return "User{" +

    "id=" + id +

    ", name='" + name + '\'' +

    ", age=" + age +

    '}';

    }

    }

      在UserBeanService中,写入如下代码:

    package com.sjj.service;

    public class UserBeanService {

    }

      在DBTools中,写入如下代码:

    package com.sjj;

    import org.apache.ibatis.io.Resources;

    import org.apache.ibatis.session.SqlSessionFactory;

    import org.apache.ibatis.session.SqlSessionFactoryBuilder;

    import java.io.IOException;

    import java.io.Reader;

    /**

    * @author jun

    * @date 2019/1/31

    */

    public class DBtools {

    private static SqlSessionFactory sqlSessionFactory;

    static {

    try {

    Reader reader = Resources.getResourceAsReader("config/SqlMapConfig.xml");

    sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    public static SqlSessionFactory getSqlSessionFactory(){

    return sqlSessionFactory;

    }

    }

      在mysql.properties中,写入如下代码(注意,这里需要根据没人配置的不同有所更改):

    jdbc.driver=com.mysql.jdbc.Driver

    jdbc.url=jdbc:mysql://localhost:3306/sjjdata?useSSL=false

    jdbc.username=你的账号,一般是root

    jdbc.password=你的密码,安装的时候你自己配的

      在SqlMapperConfig.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文件 -->

    <properties resource="config/mysql.properties"></properties>

    <!-- 全局配置 -->

    <settings>

    <!-- 打开延迟加载开关 -->

    <setting name="lazyLoadingEnabled" value="true"/>

    <!-- 将积极加载改为消极加载即按需加载 -->

    <setting name="aggressiveLazyLoading" value="false"/>

    </settings>

    <!-- 定义别名 -->

    <typeAliases>

    <!-- 一个一个地定义 -->

    <!-- <typeAlias type="com.gjh.domain.User" alias="user"/> -->

    <!-- 指定包名定义,别名就是类名,首字母大小写都可以 -->

    <package name="com.sjj.entity"/>

    </typeAliases>

    <!-- 和spring整合后 environments将废除 -->

    <environments default="development">

    <environment id="development">

    <!-- 使用JDBC事务管理,事务控制由mybatis,另一种类型为MANAGED,此配置从来不提交或回滚事务 -->

    <transactionManager type="JDBC"/>

    <!-- 数据库连接池,由mybatis type的值有UNPOOLED、POOLED、JNDI三种数据源

    不同的数据源有不同的配置属性 -->

    <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>

    <!-- 当映射文件mapper与接口类名一致且在同一个路径下时可以用class引入 -->

    <!-- <mapper class="com.sjj.dao.UserBeanMapper"/>-->

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

    <!-- 通过配置文件的位置加载——一次加载一个 -->

    <!-- <mapper class="com.gjh.mapper.OrdersMapper"/>-->

    <!-- 通过包名加载——加载包内的所有配置文件-->

    <!-- <package name="mapper"/>-->

    </mappers>

    </configuration>

      在log4j2.xml中,写入如下代码:

    <?xml version="1.0" encoding="UTF-8"?>

    <Configuration>

    <Appenders>

    <Console name="STDOUT" target="SYSTEM_OUT">

    <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>

    </Console>

    <RollingFile name="RollingFile" fileName="logs/strutslog1.log"

    filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">

    <PatternLayout>

    <Pattern>%d{MM-dd-yyyy} %p %c{1.} [%t] -%M-%L- %m%n</Pattern>

    </PatternLayout>

    <Policies>

    <TimeBasedTriggeringPolicy />

    <SizeBasedTriggeringPolicy size="1 KB"/>

    </Policies>

    <DefaultRolloverStrategy fileIndex="max" max="2"/>

    </RollingFile>

    </Appenders>

    <Loggers>

    <Logger name="com.opensymphony.xwork2" level="WAN"/>

    <Logger name="org.apache.struts2" level="WAN"/>

    <Root level="warn">

    <AppenderRef ref="STDOUT"/>

    </Root>

    </Loggers>

    </Configuration>

      在appTest中,写入如下代码:

    package com.sjj.test;

    import com.sjj.DBtools;

    import com.sjj.dao.UserBeanMapper;

    import com.sjj.entity.UserBeanVO;

    import org.apache.ibatis.session.SqlSession;

    import org.apache.ibatis.session.SqlSessionFactory;

    public class appTest {

    public static void main(String[] args){

    //1.创建sqlsessionFactory

    SqlSessionFactory sqlSessionFactory = DBtools.getSqlSessionFactory();

    //2.创建SqlSession

    SqlSession session = sqlSessionFactory.openSession();

    //3.session 中创建相应的接口代理类,即mapper对象

    UserBeanMapper userBeanMapper = session.getMapper(UserBeanMapper.class);

    System.out.println(userBeanMapper.queryAll());

    try {

    System.out.println(userBeanMapper.deleteUserByName("jun"));

    UserBeanVO u1 = new UserBeanVO();

    u1.setAge(16);

    u1.setName("Nausicaa");

    u1.setId(1);

    System.out.println(userBeanMapper.insertUser(u1));

    session.commit();//一定要提交,不然所有增删改操作不会生效的

    System.out.println(userBeanMapper.queryAll());

    }catch (Exception e){

    session.rollback();//回滚

    }

    }

    }

      最终运行程序,跑出的结果如下所示:

        去MySQL里面查,可以发现,上一篇推送《读书笔记6:<风之谷>》中的主角,娜乌西卡的信息,已经被登记到了数据库之中。

    四、总结

        谢特,怎么又有这么多字……

    相关文章

      网友评论

        本文标题:Mybatis之旅(序)

        本文链接:https://www.haomeiwen.com/subject/nwmgchtx.html