• MyBatis基础


    MyBatis

    MyBatis是java平台下一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,简单普通的 Java对象)映射成数据库中的记录。

    其前身为apache的ibatis后来迁移到Gihub并更名为MyBatis

    特点:

    ​ 1.轻量级自身不依赖其他任何JAR,但需要提供JDBC实现

    ​ 2.灵活,更加适用于需求变化频繁的互联网应用

    ​ 3.学习成本低,相比ORM框架而言,掌握MyBatis的使用是很轻松的

    在结构中的位置

    可以看出MyBatis处在DAO(数据访问对象)的位置,回顾一下DAO的工作职责:

    ​ 连接数据库

    ​ 接收输入数据

    ​ 拼接并执行SQL

    ​ 解析并返回结果

    为什么需要MyBatis

    使用JDBC完成DAO层存在以下问题

    • 每次操作都需要手动的创建连接,最后关闭连接

      对于重复代码通常开发者都会进行封装,但是由于每个人的编码风格不同导致封装的代码也没有固定的套路

      MyBatis将数据库连接相关的参数放到配置XML中并封装了创建连接的代码
    • 频繁的创建和销毁连接

      由于数据库连接使用的是TCP长连接,并发量大的系统中,这样的方式会导致数据库连接资源耗尽

      MyBatis本身实现了连接池,可以解决这一问题,当然后续会更换其他更好的连接池
    • 接受参数拼接SQL语句并执行

      每一条SQL语句都是直接写在代码中(硬编码),如果后期需求发生变化,则需要修改源码中的SQL,然后重新编译,测试.....

      MyBatis将SQL语句从代码中剥离到Mapper.xml映射文件中
    • 解析结果

      JDBC返回的是ResultSet,必须手动将其映射到一个个的对象中,同样是重复度很高的代码;并且存在硬编码问题

      MyBatis实现了入参映射到SQL参数,以及结果集映射到POJO对象

    更多功能

    MyBatis在解决上述问题的同时提供了更多实用的功能

    • 动态SQL,即在SQL语句中可以包含逻辑处理(判断,循环等....)

    • 高级映射,支持一对一,一对多映射

    • 动态代理Mapper,使得可以用面向对象的方式来完成数据库操作

    • 逆向工程,根据表结构自动生成,POJO,Mapper映射和Mapper接口,包含简单的CRUD

    MyBatis构架

    点击查看源网页

    • SqlMapConfig.xml作为全局配置,指定MyBatis的基本参数,如运行环境(开发,发布),事务管理器,数据来源等; 以及需要加载的mapper映射文件(从源码中剥离出来的SQL语句)

    • SqlSessionFactory,负责读取SqlMapConfig中的参数创建会话

    • SqlSession,通过SqlSessionFactory获取一个Session(会话)

    • Executor 真正负责执行sql语句的对象

    • MappedStatement用于将输入参数映射到sql语句,以及结果集映射到POJO

    上述构架中,SqlSession以下的部分是MyBatis封装好的,SqlSession负责调用它们完成操作; 开发过程中不需要涉及(特殊需求除外);

    另外SqlSessionFactory和SqlSession也可以通过简单的代码获取到,后续Spring框架能够自动创建它们

    所以使用MyBatis的重点就落在了SqlMapConfig.xml以及Mapper.xml

    CRUD入门

    环境搭建

    官方文档:https://mybatis.org/mybatis-3/getting-started.html

    数据库脚本:链接: https://pan.baidu.com/s/1UCOKluLqqkZ8PNMoie_0vw 提取码: h43m

    1. 创建项目

      这里采用Maven来引入MyBatis,项目采用普通的Java项目,不使用Maven骨架

    2. 添加依赖

      <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target>
      </properties>
      <dependencies>
      <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version>
          </dependency>
          <dependency>
      <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.17</version>
          </dependency>
          <dependency>
      <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version>
          </dependency>
          <dependency>
      <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version>
          </dependency>
      </dependencies>
      
    3. 提供配置文件

      1. MyBatis全局配置

        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 default="development">
        <!--        可配置多个环境  并指定默认使用的环境-->
                <environment id="development">
        <!--            指定事务管理器-->
                    <transactionManager type="JDBC"/>
        <!--            指定数据源 就是数据来自哪里 这里默认使用MyBatis自带的连接池-->
                    <dataSource type="POOLED">
                        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <!--                //表示本机 localhost  &amp;就是&  xml中&需要转译-->
                        <property name="url" value="jdbc:mysql:///mybatisDB?serverTimezone=Asia/Shanghai&amp;characterEncoding=utf8"/>
                        <property name="username" value="root"/>
                        <property name="password" value="admin"/>
                    </dataSource>
                </environment>
            </environments>
        <!--    指定要加载的映射文件-->
            <mappers>
                <mapper resource="mapper/ProductsMapper.xml"/>
            </mappers>
        </configuration>
        
        
        
        
      2. log4日志模块,定义输出格式的配置

        log4j.properties

        # Global logging configuration
        log4j.rootLogger=DEBUG, stdout  
        # Console output... 
        log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
        log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 
        log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
        

    查询数据

    查询单个

    1. 创建并编写Mapper

    ProductsMapper.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出现相同的sql时区分不同包-->
    <mapper namespace="com.yyh.UserMapper">
    
    		<!--查询语句
        id用于表示这条sql
        
        parameterType 表示 sql语句接受一个整数参数
        
        resultType表示 将结果映射到Products对象中
        
        #{} 表示一个站位符等同于 ?
                若输入参数是基础数据类型则可以随意写
                若输入是一个POJO则写属性名称-->
        <select id="selectProductBtId" parameterType="int" resultType="com.yyh.pojo.Products">
            select *from products where pid = #{pid}
        </select>
      
    </mapper>
    

    ​ 不要忘记将这个mapper配置到mybatis-config.xml中

        <mappers>
            <mapper resource="mapper/ProductsMapper.xml"/>
        </mappers>
    
    1. 执行测试
     @Test
        public void TestSelect() throws IOException {
            //获取的工厂构造器
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //加载配置文件
            InputStream stream = Resources.getResourceAsStream("mybatis-config.xml");
            //获得会话工厂
            SqlSessionFactory factory = builder.build(stream);
            //获得会话
            SqlSession sqlSession = factory.openSession();
    
            //执行sql
            Products product = sqlSession.selectOne("selectProductBtId", 1);
            System.out.println(product);
        }
    

    查询多个

    需求:使用模糊查询名字中带有新疆的数据

    1. 修改mapper增加标签

      <select id="selectProductLikeName" parameterType="string" resultType="com.yyh.pojo.Products">
        select *from products where pname like "%${name}%"
      </select>
      
    2. 执行测试

      @Test
      public void selectTest2() throws IOException {
          //获得会话
          SqlSession sqlSession = factory.openSession();
          //执行sql
          List<Products> products = sqlSession.selectList("selectProductLikeName", "新疆");
          System.out.println(products);
          sqlSession.close();
      }
      

      由于多个测试方法都需要工厂所以讲工厂作为属性并在,@Before中进行初始化

      public class MyBatisTest {
          private SqlSessionFactory factory;
          @Before
          public  void init() throws IOException {
              //获取的工厂构造器
              SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
              //加载配置文件
              InputStream stream = Resources.getResourceAsStream("mybatis-config.xml");
              //获得会话工厂
              factory = builder.build(stream);
          }
      ........}
      

      需要注意的是:在mapper中当需要做将参数进行字符串拼接时则不能在使用#{} 需更换为${}表示将参数结果提取并拼接到字符串中

      注意了:若MyBatis版本低于3.5.2 则在字符串中使用#{xxx}的方式将导致找不到属性异常,在低版本中MyBatis将#{xxx}中的xxx当做参数的属性去参数中查找get方法(很明显找不到),在字符串内和字符串外获取属性的行为竟然不同,,,,,好在3.5.2解决了这个问题

    插入数据

    1. 修改mapper增加标签

      <!-- insert没有返回值-->
      <insert id="insertProduct" parameterType="com.yyh.pojo.Products">
        insert into products values(null,#{pname},#{price},#{pdate},#{cid})
      </insert>
      
    2. 执行测试

      @Test
      public void insertTest() {
          //设置自动提交为true 默认为false  
          SqlSession session = factory.openSession(true);
          //实例化一个商品
          Products p = new Products();
          p.setPname("虎邦辣酱");
          p.setPrice(5.5f);
          p.setPdate(new Date());
          p.setCid("s001");
          session.insert("insertProduct",p);
          //session.commit();//手动commit
          session.close();
      }
      
      强调:

      当sql为update insert delete时需要commit才会生效,SqlSession默认不自动提交的,可以在获取SqlSession时指定自动提交,也可以在执行完后手动调用commit;

      sql为update insert delete时返回值为受影响行数

    3. 获取插入记录的id

      很多情况下需要获取刚刚添加的记录的id用来做表关联,要获得id有两种方式

      3.1对于支持自增的数据库MySQL

      <insert id="insertProduct" parameterType="com.yyh.pojo.Products" keyProperty="pid" useGeneratedKeys="true">
        insert into products values(null,#{pname},#{price},#{pdate},#{cid})
      </insert>
      MyBatis会把id存储到传入对象的pid属性中
      

      3.2兼容不支持自增的数据库

      <!--插入数据    -->
          <insert id="insertProduct" parameterType="com.yyh.pojo.Products" >
              insert into products values(null,#{pname},#{price},#{pdate},#{cid})
              <!--指定如何获取id 并放入对象某个属性中 -->
              <selectKey resultType="int" keyProperty="pid" order="AFTER" >
                  select last_insert_id();
              </selectKey>
          </insert>
      

      注意:select last_insert_id();是mysql的函数,oracle没有,那就需要将其替换为oracle中生产id的函数,selectKey的原理是执行这个sql函数,然后将结果放入对象的属性中,order指定id放入对象属性是在执行sql前或者后

      关于before和after的选择,要根据id的来源是自增的还是自己编写语句获取的,如下:

      image-20191229225942986

    更新数据

    1. 修改mapper增加标签

      <!--更新数据    -->
          <update id="updateProduct" parameterType="com.yyh.pojo.Products">
              update products set
                  pname = #{pname},
                  price = #{price},
                  pdate = #{pdate},
                  cid = #{cid}
              where pid = #{pid}
          </update>
      
    2. 执行测试

      @Test
      public void updateTest() {
          SqlSession session = factory.openSession();
          //先获取一条记录
          Products p = session.selectOne("selectProductBtId", 1);
          //更新属性
          p.setPrice(99.99f);
          //执行更新
          int count = session.update("updateProduct", p);
          System.out.println("update count :"+count);
          //提交事务
          session.commit();
          session.close();
      }
      

    删除数据

    1. 修改mapper增加标签

      <!--通过id删除    -->
      <delete id="deleteProductById" parameterType="int">
        delete from products where
        pid = #{pid}
      </delete>
      
    2. 执行测试

      @Test
      public void deleteTest() {
          SqlSession session = factory.openSession();
          int count = session.delete("deleteProductById", 1);
          System.out.println("delete count :"+count);
          session.commit();
          session.close();
      }
      

    下一章 MyBatis进阶

  • 相关阅读:
    大数据基本概念及Hadoop技术基础
    基于 ReliefF和K-means算法的应用
    利用Hadoop和Spark处理用户心跳周期数据
    Java线程池源码解析及高质量代码案例
    muleESB的第一个开发实例-HelloWorld(二)
    [USACO11JAN]道路和飞机Roads and Planes
    CH6101 最优贸易
    POJ3662 Telephone Lines
    扫描线+线段树例题(HDU1542)
    关于Dinic算法的几点讨论
  • 原文地址:https://www.cnblogs.com/yangyuanhu/p/12117159.html
Copyright © 2020-2023  润新知