zoukankan      html  css  js  c++  java
  • myBatis基础学习

    本文记录了mybatis中基础知识的学习,下一篇会介绍mybatis的高级用法,相关代码和参考资料在这里,下面正式开始学习


    1.原生态JDBC程序中的问题总结

    • 传统使用JDBC对java文件与数据库进行连接的步骤和代码如下:

      首先在导入jdbc驱动包之后,创建数据库并编写数据库连接代码

    package jdbc_test;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    import com.mysql.jdbc.Driver;
    
    public class jdbcTest {
    
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
            // TODO Auto-generated method stub
            // 数据库的连接
            Connection connection = null;
            // 预编译的Statement,使用预编译的Statement提高数据库的性能
            // 通过预编译的Statement向数据库发生sql语句,数据库要对sql语句进行编译,编译完之后数据库会对得到的结果集存到数据库端的缓存中
            // 下一次再发送相同的sql语句,数据库则不用重新编译,直接从缓存中拿来结果集即可,所以提高了数据库的性能。
            PreparedStatement preparedStatement = null;
            // 结果集
            ResultSet resultSet = null;
            try {
                // 加载数据库驱动
                Class.forName("com.mysql.jdbc.Driver");
                // 通过驱动管理类获取数据库连接
                connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis_learning?useSSL=false",
                        "root", "7458");
                // 定义sql语句,其中?表示占位符
                String sqlString = "select * from user where username = ?";
                // 获取预处理statement
                preparedStatement = connection.prepareStatement(sqlString);
                // 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
                preparedStatement.setString(1, "王五");
                // 向数据库发出sql执行查询,查询出结果集
                resultSet = preparedStatement.executeQuery();
                // 遍历查询结果集
                while (resultSet.next()) {
                    System.out.println(resultSet.getString("id") + " " + resultSet.getString("username"));
                }
            } finally {
                // TODO: handle finally clause
                // 释放资源(倒着释放)
                if (resultSet != null) {
                    try {
                        resultSet.close();
                    } catch (SQLException e) {
                        // TODO: handle exception
                        e.printStackTrace();
                    }
                }
                if (preparedStatement != null) {
                    try {
                        preparedStatement.close();
                    } catch (SQLException e) {
                        // TODO: handle exception
                        e.printStackTrace();
                    }
                }
                if (connection != null) {
                    try {
                        connection.close();
                    } catch (SQLException e) {
                        // TODO: handle exception
                        e.printStackTrace();
                    }
                }
            }
        }
    
    }
    View Code
    • 分析问题:
      • 数据库的连接,使用时就创建,不使用时立即释放,对数据库进行频繁的连接开启和关闭,造成数据库资源的浪费,影响数据库的性能;
        • 设想:使用数据库连接池管理数据库的连接。
      • 将sql语句硬编码到java文件中,如果sql语句修改,需要重新编译java代码,不利于系统维护。
        • 设想:将sql语句配置到xml文件中,即使sql变化,不需要对java代码进行重新编译。
      • 向preparedStatement中设置参数,对占位符设置和参数值的设置同样硬编码到java代码中,不利于系统维护。
        • 设想:将sql语句及占位符号和参数全部配置到xml中。
      • 从resultSet中遍历结果集数据时,也存在硬编码,将获取表的字段进行硬编码,不利于系统维护。
        • 设想:将查询的结果集自动映射成java对象。

    2.mybatis框架 

    • 什么是mybatis

      mybatis是一个持久层的框架,是apache下的顶级项目,现在被托管到github上,它可以让程序将主要的精力放在sql上,通过mybatis提供的映射方式,自由灵活的生成(半自动化,大部分需要程序员编写sql)满足需要的sql语句,将preparedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象(输出映射)。

    • mybatis的框架结构

      

    3.mybatis的工程结构及入门增删改查的开发步骤

    1. 设置全局配置文件: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>
          <!-- 数据库 -->
          <!-- 和spring整合后, environments配置将废除 -->
          <environments default="development">
              <environment id="development">
                  <!-- 使用jdbc事务管理,单独使用时事务控制由mybatis管理 -->
                  <transactionManager type="JDBC" />
                  <!-- 数据库连接池,单独使用时由mybatis管理 -->
                  <dataSource type="POOLED">
                      <property name="driver" value="com.mysql.jdbc.Driver" />
                      <property name="url"
                          value="jdbc:mysql://localhost:3306/mybatis_learning?useSSL=false" />
                      <property name="username" value="root" />
                      <property name="password" value="7458" />
                  </dataSource>
              </environment>
          </environments>
          <!-- 加载映射文件 -->
          <mappers>
              <mapper resource="com/basicOp/mapper/UserMapper.xml" />
          </mappers>
      </configuration>
      View Code
    2. 设置日志文件:log4j.properties
      # Global logging configuration
      # 在开发环境下日志级别是DEBUG,生产环境设置为info或error
      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
      View Code
    3. 定义自定义pojo对象类型,要与数据库中的数据类型对应
      package com.basicOp.pojo;
      
      import java.util.Date;
      
      public class User {
          private int id;
          private String username;// 用户姓名
          private String sex;// 性别
          private Date birthday;// 生日
          private String address;// 地址
      
          public int getId() {
              return id;
          }
      
          public void setId(int id) {
              this.id = id;
          }
      
          public String getUsername() {
              return username;
          }
      
          public void setUsername(String username) {
              this.username = username;
          }
      
          public String getSex() {
              return sex;
          }
      
          public void setSex(String sex) {
              this.sex = sex;
          }
      
          public Date getBirthday() {
              return birthday;
          }
      
          public void setBirthday(Date birthday) {
              this.birthday = birthday;
          }
      
          public String getAddress() {
              return address;
          }
      
          public void setAddress(String address) {
              this.address = address;
          }
      
          @Override
          public String toString() {
              return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address="
                      + address + "]";
          }
      
      }
      View Code
    4. 设置mapper文件,准备操作数据库,其命名格式按照UserMapper.xml这种与pojo实体类关联的驼峰格式,这样的好处是代理可以自动识别。最后将映射文件加入到全局配置文件中。
      <?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表示命名空间,每一个命名空间代表着一个pojo的映射器 -->
      <mapper namespace="com.basicOp.mapper.UserMapper">
          <!-- id:标识映射文件中的sql,sql语句封装到mappedStatement对象中,所以将id称为statement的id 
               parameterType:指定输入参数的类型 
               resultType:不管返回是单条还是多条记录,其指定的的单条sql输出结果所映射的java对象类型 #{}:表示占位符 -->
          <select id="findUserById" parameterType="int" resultType="com.basicOp.pojo.User">
              select
              * from user where id = #{id}
          </select>
      
          <select id="findUserByName" parameterType="string"
              resultType="com.basicOp.pojo.User">
              select * from user where username like concat('%',
              #{username}, '%')
          </select>
          
          <!-- parameterType在插入时是对应的pojo对象类型 #{}里面是pojo的属性值,mybatis通过OGNL获取对象的属性值 -->
          <insert id="insertUser" parameterType="com.basicOp.pojo.User">
              insert into user
              (username,birthday,sex,address)
              values
              (#{username},#{birthday},#{sex},#{address})
          </insert>
          
          <delete id="deleteUser" parameterType="java.lang.Integer">
              delete from user where id = #{id}
          </delete>
          
          <update id="updateUser" parameterType="com.basicOp.pojo.User">
              update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
          </update>
      </mapper>
      View Code
    5. 创建与mapper所对应的接口文件,命名按照上面的mapper文件一样UserMapper.java,里面包括了操作数据库的方法,方法名与mapper中的id是一样的。
      package com.basicOp.mapper;
      
      import java.util.List;
      
      import com.basicOp.pojo.User;
      
      public interface UserMapper {
          public User findUserById(int id);
          public List<User> findUserByName(String userName);
          public int insertUser(User user);
          public int deleteUser(int id);
          public int updateUser(User user);
      }
      View Code
    6. 按照框架编写程序,包括SqlSessionFactory、SqlSession等,将创建SqlSessionFactory和SqlSession直接放到一个工具类包里,后续在测试类中可直接调用。
      package com.basicOp.utils;
      
      import java.io.IOException;
      import java.io.InputStream;
      
      import org.apache.ibatis.io.Resources;
      import org.apache.ibatis.session.SqlSession;
      import org.apache.ibatis.session.SqlSessionFactory;
      import org.apache.ibatis.session.SqlSessionFactoryBuilder;
      
      public class SqlSessionFactoryUtils {
          public static final Class<SqlSessionFactoryUtils> LOCK = SqlSessionFactoryUtils.class;
          private static SqlSessionFactory sqlSessionFactory = null;
      
          private SqlSessionFactoryUtils() {
          }
      
          public static SqlSessionFactory getSqlSessionFactory() {
              synchronized (LOCK) {
                  if (sqlSessionFactory != null) {
                      return sqlSessionFactory;
                  }
                  try {
                      //获得mybatis配置文件
                      String resource = "mybatis-config.xml";
                      //得到配置文件流
                      InputStream inputStream = Resources.getResourceAsStream(resource);
                      //通过配置文件流创建会话工厂,传入mabatis的配置文件信息
                      sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
                  } catch (IOException e) {
                      // TODO: handle exception
                      e.printStackTrace();
                  }
                  return sqlSessionFactory;
              }
          }
      
          public static SqlSession openSqlSession() {
              if (sqlSessionFactory == null) {
                  getSqlSessionFactory();
              }
              //通过工厂得到SqlSession
              return getSqlSessionFactory().openSession();
          }
      }
      View Code
    7. 编写测试类
      package com.basicOp.main;
      
      import java.util.Date;
      import java.util.List;
      
      import org.apache.ibatis.session.SqlSession;
      import org.apache.log4j.Logger;
      
      import com.basicOp.mapper.UserMapper;
      import com.basicOp.pojo.User;
      import com.basicOp.utils.SqlSessionFactoryUtils;
      
      public class basicOpMain {
      
          public static void main(String[] args) {
              // TODO Auto-generated method stub
              // testFindUserById();
              // testFindUserByName();
              // testInsertUser();
              // testDeleteUser();
              testUpdateUser();
      
          }
      
          // 获得通过id查询得到的User结果
          public static void testFindUserById() {
              Logger logger = Logger.getLogger(basicOpMain.class);
              SqlSession sqlSession = null;
              try {
                  // 创建会话
                  sqlSession = SqlSessionFactoryUtils.openSqlSession();
                  // 利用sqlSession获得对应的mapper接口后,开始操作数据库
                  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                  User user = userMapper.findUserById(1);
                  logger.info(user.toString());
              } finally {
                  // TODO: handle finally clause
                  if (sqlSession != null) {
                      sqlSession.close();
                  }
              }
          }
      
          // 利用username进行模糊查询
          public static void testFindUserByName() {
              Logger logger = Logger.getLogger(basicOpMain.class);
              SqlSession sqlSession = null;
              try {
                  // 创建会话
                  sqlSession = SqlSessionFactoryUtils.openSqlSession();
                  // 利用sqlSession获得对应的mapper接口后,开始操作数据库
                  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
      
                  List<User> users = userMapper.findUserByName("小明");
                  for (User user : users) {
                      logger.info(user.toString());
                  }
              } finally {
                  // TODO: handle finally clause
                  if (sqlSession != null) {
                      sqlSession.close();
                  }
              }
          }
      
          // 插入数据
          public static void testInsertUser() {
              Logger logger = Logger.getLogger(basicOpMain.class);
              SqlSession sqlSession = null;
              try {
                  // 创建会话
                  sqlSession = SqlSessionFactoryUtils.openSqlSession();
                  // 利用sqlSession获得对应的mapper接口后,开始操作数据库
                  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                  User user = new User();
                  user.setUsername("许昕");
                  user.setBirthday(new Date());
                  user.setSex("1");
                  user.setAddress("中国徐州");
                  userMapper.insertUser(user);
                  // 提交事务
                  sqlSession.commit();
                  logger.info(user);
              } finally {
                  // TODO: handle finally clause
                  if (sqlSession != null) {
                      sqlSession.close();
                  }
              }
          }
      
          // 删除数据
          public static void testDeleteUser() {
              Logger logger = Logger.getLogger(basicOpMain.class);
              SqlSession sqlSession = null;
              try {
                  // 创建会话
                  sqlSession = SqlSessionFactoryUtils.openSqlSession();
                  // 利用sqlSession获得对应的mapper接口后,开始操作数据库
                  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                  userMapper.deleteUser(28);
                  // 提交事务
                  sqlSession.commit();
      
              } finally {
                  // TODO: handle finally clause
                  if (sqlSession != null) {
                      sqlSession.close();
                  }
              }
          }
      
          // 更新数据
          public static void testUpdateUser() {
              Logger logger = Logger.getLogger(basicOpMain.class);
              SqlSession sqlSession = null;
              try {
                  // 创建会话
                  sqlSession = SqlSessionFactoryUtils.openSqlSession();
                  // 利用sqlSession获得对应的mapper接口后,开始操作数据库
                  UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
                  User user = new User();
                  user.setId(27);
                  user.setUsername("许昕");
                  user.setAddress("江苏徐州");
                  userMapper.updateUser(user);
                  // 提交事务
                  sqlSession.commit();
      
              } finally {
                  // TODO: handle finally clause
                  if (sqlSession != null) {
                      sqlSession.close();
                  }
              }
          }
      
      }
      View Code

    4.myBatis开发dao方法(mapper代理的方法)

    • SqlSession使用范围
      • SqlSessionFactoryBuilder

        通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory,将SqlSessionFactoryBuilder当成一个工具类使用即可,不需要使用单例管理SqlSessionFactoryBuilder,在需要创建SqlSessionFactory时候,只需要new一次SqlSessionFactoryBuilder即可。

      • SqlSessionFactory

        通过SqlSessionFactory创建SqlSession,使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例),将来mybatis和spring整合后,使用单例模式管理sqlSessionFactory。

      • SqlSession

        SqlSession是一个面向用户(程序员)的接口,SqlSession中提供了很多操作数据库的方法:如:selectOne(返回单个对象)、selectList(返回单个或多个对象),SqlSession是线程不安全的,在SqlSesion实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。所以SqlSession最佳应用场合在方法体内,定义成局部变量使用。

    • 原始dao开发的问题

      在myBatis中若按照原始的dao方法进行开发,首先要定义好mapper映射文件中每个功能的接口,再实现该接口,然后进行测试,这就会出现如下问题:

    1. dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。
    2. 调用SqlSession方法时将statement的id硬编码了。
    3. 调用SqlSession方法时传入的变量,由于SqlSession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。

      使用mapper代理的开发,在编写完mapper.xml映射文件后,只需要编写对应mapper接口即可,myBatis可以自动根据接口利用反射实现类的代理对象,mapper接口中的接口名、方法名、参数名、返回值要与mapper文件中对应。

    5.全局配置文件mybatis-config.xml中的元素属性

      在全局配置文件中,元素属性的设置是有顺序的,要按照如下顺序进行设置和定义:

      

    • properties属性

      将数据库的连接参数单独的设置在jdbc.properties中,只需要在全局配置文件中加载jdbc.properties的属性值即可,避免了在全局配置文件中的硬编码,方便统一管理。

      注意: MyBatis 将按照下面的顺序来加载属性:

    • 在 properties 元素体内定义的属性首先被读取。
    • 然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。
    • 最后读取parameterType传递的属性,它会覆盖已读取的同名属性。

       建议:不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中。在properties文件中定义属性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX

    • setting全局参数配置

      mybatis框架在运行时可以调整一些运行参数,比如:开启二级缓存、开启延迟加载等,会影响全局的运行行为,需要的时候再使用。

      

      

    • typeAliases别名属性

      在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。

      mybatis默认支持别名:

      

      也可以进行自定义别名设置,包括单个别名设置和批量别名设置。

    • typeHandlers类型处理器

      mybatis中通过typeHandlers完成jdbc类型和java类型的转换,通常情况下mybatis提供的类型处理器满足日常需要,不需要自定义。

      

    • objectFactory对象工程和plugins插件一般不用,用的时候查看开发手册即可,environments环境属性即将要被废弃。

    • mapper映射器

      可以通过resource加载单个映射文件;

      可以通过mapper接口加载单个mapper;

      可以批量加载mapper;

    6.输入映射

      通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo包装类型,具体使用方法参考使用手册,pojo包装类型很重要,会比较常用。

    7.输出映射

      使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功,如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间做一个映射关系,其他简单的返回的具体使用方法参考使用手册。

    8.动态sql

      动态sql可以使得对sql语句的使用更加灵活,通过表达式进行判断,对sql进行灵活拼接、组装,具体使用方法可参考使用手册。

  • 相关阅读:
    112、TensorFlow初始化变量
    111、TensorFlow 初始化变量
    110、TensorFlow张量值的计算
    109、TensorFlow计算张量的值
    108、TensorFlow 类型转换
    107、TensorFlow变量(三)
    106、TensorFlow变量 (二) reshape
    105、TensorFlow的变量(一)
    104、Tensorflow 的变量重用
    103、Linux 编译 Kaldi 语音识别工具
  • 原文地址:https://www.cnblogs.com/yunkaiL/p/11393243.html
Copyright © 2011-2022 走看看