MyBatis基础(二)

MyBatis基础(二)

MyBatis接口开发

MyBatis接口开发其实就是:mapper(映射)动态代理方式的crud。
原则:约定优于配置。
硬编码方式
	abc.java:
		Configuration conf = new Configuration();
		conf.setName("myProject") ;
配置方式:
	abc.xml:
		<name>myProject</name>

约定:默认值就是myProject

具体实现的步骤

  • 约定的目标:省略掉statement,即根据约定 直接可以定位出SQL语句

    • 基础方式执行SQL

      SqlSession session = sessionFacotry.openSession() ;
      //namespace.id 找到对应的 SQL 
      String statement = "org.lanqiao.entity.studentMapper.queryStudentByStuno";
      Student student = session.selectOne(statement,1) ;
      
  • 基础环境

    • 数据库和实体类

    • mybatis.jar/数据库驱动jar包、conf.xml、mapper.xml

  • 编写接口,要遵循以下约定:

    • namespace的值 ,就是 接口的全类名( 接口 - mapper.xml 一一对应)

    • 方法名和mapper.xml(映射)文件中标签的id值相同

    • 方法的 输入参数 和 mapper.xml文件中标签的 parameterType类型一致 (如果mapper.xml的标签中没有 parameterType,则说明方法没有输入参数)

    • 方法的返回值 和 mapper.xml文件中标签的 resultType类型一致 (无论查询结果是一个 还是多个(student、List<Student>),在mapper.xml标签中的resultType中只写 一个(Student);如果没有resultType,则说明方法的返回值为void

    • 接口 如:

      package org.lanqiao.mapper;
      
      import java.util.List;
      import org.lanqiao.entity.Student;
      //操作Mybatis的接口
      public interface StudentMapper {
      
          //根据学号查询学生信息
          //public abstract Student queryStudentByStuno(int stuno);
          Student queryStudentByStuno(int stuno);	
      }
      
    • Mapper.xml 如:

      <!-- namespace:该mapper.xml映射文件的 唯一标识 -->
      <!-- 根据约定,namespace值 和 接口的全路径一样 -->
      <mapper namespace="org.lanqiao.mapper.StudentMapper">
          
          <!--parameterType:输入参数的类型,和接口中对应方法的输入参数类型一致
       	resultType:查询返回结果值的类型,和接口中方法的 返回值类型 或 泛型 一致 -->
      
          <select id="queryStudentByStuno" 	parameterType="int"  	resultType="org.lanqiao.entity.Student" >
              select * from student where stuno = #{stuno}
          </select>
      </mapper>
      
  • 匹配过程(约定过程)分析

    1. 根据 接口名 找到 对应的mapper.xml文件(根据的是namespace = 接口全类名)

    2. 根据 接口的 方法名 找到 mapper.xml文件中的SQL标签 (方法名 = SQL标签 id 值)

    3. 当我们调用接口中的方法时,程序能自动定位到 某一个Mapper.xml文件中的SQL标签

      • 习惯:SQL映射文件(mapper.xml)和 接口 通常放在同一个包中 (注意修改conf.xml中加载mapper.xml文件的路径)
  • 执行具体代码实现(StudentTest.java)

    //根据学号查询单个学生
    public static void queryStudentByStuno() throws IOException {
        //Connection -  SqlSession操作MyBatis
        //conf.xml - > reader
        Reader reader = Resources.getResourceAsReader("conf.xml") ;
        //reader  ->SqlSession
    
        //可以通过build的第二参数 指定数据库环境
        SqlSessionFactory sessionFacotry = new SqlSessionFactoryBuilder().build(reader,"development") ;
        SqlSession session = sessionFacotry.openSession() ;
    
        /* 与基础方式的不同之处:
        通过session对象获取接口(session.getMapper(接口.class);),再调用该接口中的方法,程序会自动	  执行该方法对应的SQL。
        */
        StudentMapper studentMapper = session.getMapper(StudentMapper.class) ;
        Student student = studentMapper.queryStudentByStuno(2) ;//接口中的方法->SQL语句
    
        System.out.println(student);
        session.close();
    }
    

优化

  • conf.xml中的数据库配置信息抽取成配置文件,再进行读取

    • properties文件信息如下:

      driver=oracle.jdbc.OracleDriver
      url=jdbc:oracle:thin:@127.0.0.1:1521:ORCL
      username=scott
      password=tiger
      
    • conf.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  resource="db.properties"/>
          
          <!-- 通过environments的default值 和  environment的 id 来指定 MyBatis运行时的数据库环境-->
          <environments default="development">
              <!-- 开发环境(自己的计算机) -->
              <environment id="development">
                  <!-- 事务提交方式:
          JDBC:利用JDBC方式处理事务(commit  rollback  close)
          MANAGED:将事务交由 其他组件去托管(spring ,jboss),默认 会关闭连接。
      
      	配置默认不关闭连接
         <transactionManager type="MANAGED"/>
          <property name="closeConnection" value="false"/>
          -->
                  <transactionManager type="JDBC" />
                  <!-- 数据源类型:
            UNPOOLED:传统的JDBC模式(每次访问数据库,均需要 打开、关闭等数据库操作,但是 打开、关闭数据库是比较消耗性能的)
            POOLED:使用数据库连接池
            JNDI:从tomcat中获取一个内置的数据库连接池 (数据库连接池-数据源)
           -->
      
                  <dataSource type="POOLED">
                      <!-- 配置数据库信息:读取配置文件的方式 -->
                      <property name="driver" value="${driver}"/>
                      <property name="url" value="${url}"/>
                      <property name="username" value="${username}"/>
                      <property name="password" value="${password}"/>
                  </dataSource>
              </environment>
      
              <!-- 真正的项目应该在   发布的那台计算机上运行:不读取配置文件的方式 -->
              <environment id="shishi">
                  <transactionManager type="JDBC"/>
                  <dataSource type="POOLED">
                      <!-- 配置数据库信息 -->
                      <property name="driver" value="oracle.jdbc.OracleDriver"/>
                      <property name="url" value="jdbc:oracle:thin:@192.168.1.183:1521:ORCL"/>
                      <property name="username" value="scott"/>
                      <property name="password" value="tiger"/>
                  </dataSource>
              </environment>
              
              <mappers>
                  <!-- 加载映射文件 -->
                  <mapper resource="org/lanqiao/mapper/studentMapper.xml"/>
              </mappers>
              </configuration>
      

别名

  • 在Mapper.xml文件中,进行增删改查的时候,parameterType 和 resultType 的字符串过长,因此可以为其起个别名。

    • 单个别名(在conf.xml中设置)

      <configuration>
          <typeAliases>
              <!-- 单个别名(别名 忽略大小写) -->
              <typeAlias type="org.lanqiao.entity.Student" alias="student"/>
          </typeAliases>
      </configuration>
      
    • 批量别名(在conf.xml中设置)

      <configuration>
          <typeAliases>
              <!-- 批量定义别名(别名 忽略大小写),以下会自动将该包中的所有类 批量定义别名: 别名就是类名(不带包名的类名,忽略大小写)-->
              <package name="org.lanqiao.entity"/>
          </typeAliases>
      </configuration>
      

全局参数

  • conf.xml文件中配置

    <configuration>
        <settings>
            <setting name="cacheEnabled" value="false"  />
            <setting name="lazyLoadingEnabled" value="false"  />
        </settings>
    </configuration>
    

增加数据

  • 接口方法

    //增加
    void addStudent(Student student);
    
  • Mapper.xml

    <insert id="addStudent" parameterType="student" >
        insert into student(stuno,stuname,stuage,graname) values(#{stuNo},#{stuName},#{stuAge},#{graName} ) 
    </insert>
    
  • StudentTest

    Student student = new Student(13,"ww3",23,"s3");
    StudentMapper studentMapper = session.getMapper(StudentMapper.class);
    studentMapper.addStudent(student);
    

删除数据

  • 接口方法

    void deleteStudentByStuno(int stuno);
    
  • Mapper.xml

<delete id="deleteStudentByStuno"  parameterType="int">
    delete from student where stuno = #{stuno} 
</delete>
  • StudentTest

    StudentMapper studentMapper = session.getMapper(StudentMapper.class);
    studentMapper.deleteStudentByStuno(13);
    

修改数据

  • 接口方法

    //修改
    void updateStudentByStuno(Student student);
    
  • Mapper.xml

    <update id="updateStudentByStuno" parameterType="student" >
        update student set stuname=#{stuName} ,stuage=#{stuAge},graname=#{graName} where stuno=#{stuNo} 
    </update>
    
  • StudentTest

    //修改的参数
    Student student = new Student();
    //修改哪个人,where stuno =2 
    student.setStuNo(2);
    //修改成什么样子?
    student.setStuName("ls");
    student.setStuAge(24);
    student.setGraName("s1");
    //执行
    StudentMapper studentMapper = session.getMapper(StudentMapper.class);
    studentMapper.updateStudentByStuno(student);
    

查询多条数据

  • 接口方法

    //查询全部
    List<Student> queryAllStudents();
    
  • Mapper.xml

    <select id="queryAllStudents"  resultType="student" >
        select * from student 
    </select>
    
  • StudentTest

    StudentMapper studentMapper = session.getMapper( StudentMapper.class) ;
    List<Student> students = studentMapper.queryAllStudents() ;//接口的方法->SQL
    

类型转换

  • MyBatis自带一些常见的类型处理器

    如:javaType(Integer) --> jdbcType(INTEGER),自行查阅。
    
  • 自定义MyBatis类型处理器

    • 目标:java类型 – 数据库(jdbc类型)的相互转换

    • 示例

      实体类Student : boolean   stuSex
      true: 男
      false:女
      表student:number  stuSex
      1: 男
      0: 女
      
    • 实现步骤

      • 创建转换器

        • 方式一:实现TypeHandler接口,重写其方法。

          public interface TypeHandler<T> {
              /**
          
               * 用于定义在Mybatis设置参数时该如何把Java类型的参数转换为对应的数据库类型
          
               * @param ps 当前的PreparedStatement对象
          
               * @param i 当前参数的位置
          
               * @param parameter 当前参数的Java对象
          
               * @param jdbcType 当前参数的数据库类型
          
               * @throws SQLException
          
               */
              void setParameter(PreparedStatement ps, int i, T parameter,
          
                                JdbcType jdbcType) throws SQLException;
          
          
              /**
          
               * 用于在Mybatis获取数据结果集时如何把数据库类型转换为对应的Java类型
          
               * @param rs 当前的结果集
          
               * @param columnName 当前的字段名称
          
               * @return 转换后的Java对象
          
               * @throws SQLException
          
               */
              T getResult(ResultSet rs, String columnName) throws SQLException;
          
              /**
          
               * 用于在Mybatis通过字段位置获取字段数据时把数据库类型转换为对应的Java类型
          
               * @param rs 当前的结果集
          
               * @param columnIndex 当前字段的位置
          
               * @return 转换后的Java对象
          
               * @throws SQLException
          
               */
              T getResult(ResultSet rs, int columnIndex) throws SQLException;
          
              /**
          
               * 用于Mybatis在调用存储过程后把数据库类型的数据转换为对应的Java类型
          
               * @param cs 当前的CallableStatement执行后的CallableStatement
          
               * @param columnIndex 当前输出参数的位置
          
               * @return
          
               * @throws SQLException
          
               */
              T getResult(CallableStatement cs, int columnIndex) throws SQLException;
          }
          
        • 方式二:继承BaseTypeHandler类,重写其方法。(推荐)

          //BaseTypeHandler<java类型>
          public class BooleanAndIntConverter extends BaseTypeHandler<Boolean>{
          
              //java(boolean)-DB(number)
              /*
          	 * ps:PreparedStatement对象
          	 * i:PreparedStatement对象操作参数的位置
          	 * parameter:java类型的值
          	 * jdbcType:jdbc操作的数据库类型
          	 */
              @Override
              public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType)
                  throws SQLException {
                  if(parameter) {
                      //1
                      ps.setInt(i, 1); 
                  }else {
                      //0
                      ps.setInt(i, 0); 
                  }
              }
          
              //db(number)->java(boolean)
              //通过列名(columnName)拿值
              @Override
              public Boolean getNullableResult(ResultSet rs, String columnName) throws SQLException {
                  int sexNum = rs.getInt(columnName) ;//rs.getInt("stuno") ;
                  //		if(sexNum == 1)
                  //		
                  //			return true;
                  //		else {
                  //			return false ;
                  //		}
                  return sexNum == 1?true:false ;
              }
          
              //db(number)->java(boolean)
              //拿第几列(columnIndex)的值
              @Override
              public Boolean getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
                  int sexNum = rs.getInt(columnIndex) ;//rs.getInt(1)
                  return sexNum == 1?true:false ;
              }
          
              //db(number)->java(boolean)
              //通过存储过程(cs)拿值
              @Override
              public Boolean getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
                  int sexNum = cs.getInt(columnIndex) ;//rs.getInt(1)
                  return sexNum == 1?true:false ;
              }
          }
          
      • conf.xml中配置转换器

        <configuration>
            <!-- 配置转换器 -->
            <typeHandlers>
                <!-- 可以配置多个转换器 -->
                <typeHandler handler="org.lanqiao.converter.BooleanAndIntConverter" javaType="Boolean" jdbcType="INTEGER" />
            </typeHandlers>
        </configuration>
        

        编写接口方法(1)(增加)java类型 —> 数据库jdbc类型

        //带转换器的增加
        void addStudentWithConverter(Student student);
        

        Mapper.xml(1)(增加)java类型 —> 数据库jdbc类型

        <!-- 带转换器的增加 -->
        <insert id="addStudentWithConverter" parameterType="student" >
            insert into student(stuno,stuname,stuage,graname,stusex) values(#{stuNo},#{stuName},#{stuAge},#{graName} ,#{stuSex ,javaType=boolean  ,jdbcType=INTEGER   } ) 
        </insert>
        

        StudentTest(1)(增加)java类型 —> 数据库jdbc类型

        //增加学生(带转换器)
        public static void addStudentWithConverter() throws IOException {
            //Connection -  SqlSession操作MyBatis
            //conf.xml - > reader
            Reader reader = Resources.getResourceAsReader("conf.xml") ;
            //reader  ->SqlSession
            //可以通过build的第二参数 指定数据库环境
            SqlSessionFactory sessionFacotry = new SqlSessionFactoryBuilder().build(reader,"development") ;
            SqlSession session = sessionFacotry.openSession() ;
        
            Student student = new Student(63,"ww53",23,"s3");
            student.setStuSex(true);//1
        
            StudentMapper studentMapper = session.getMapper(StudentMapper.class);
            studentMapper.addStudentWithConverter(student);
        
            session.commit(); //提交事务
        
            System.out.println("增加成功");
            session.close(); //关闭会话(连接)
        }
        
      • 编写接口方法(2)(查询) 数据库jdbc类型 —> java类型

        //带转换器的查询
        Student queryStudentByStunoWithConverter(int stuno);
        
      • Mapper.xml(2)(查询)数据库jdbc类型 —> java类型

        <!-- 查询:使用了类型转换器
         1如果 类中属性 和表中的字段 类型能够合理识别 (String-varchar2),则可以使用resultType;否则(boolean-number) 使用resultMap
         2如果 类中属性名 和表中的字段名能够合理识别 (stuNo -stuno)则可以使用resultType;否则(id-stuno) 使用resultMap
          -->
        <select id="queryStudentByStunoWithConverter" 	parameterType="int"  	
                resultMap="studentResult" >
            select * from student where stuno = #{stuno}
        </select>
        
        <resultMap type="student" id="studentResult">
            <!-- 分为主键id 和非主键 result-->
            <id property="stuNo"  column="stuno"  />
            <result property="stuName"  column="stuname" />
            <result property="stuAge"  column="stuage" />
            <result property="graName"  column="graname" />
            <result property="stuSex"  column="stusex"  javaType="boolean" jdbcType="INTEGER"/>
        </resultMap>
        
        • resultMap应用场景
      • resultMap:实体类的属性、数据表的字段: 类型、名字不同时(stuno,id)

        • 一般用 resultType
      • StudentTest(2)(查询)数据库jdbc类型 —> java类型

        //查询单个学生(使用了转换器)
        public static void queryStudentByStunoWithConverter() throws IOException {
            //Connection -  SqlSession操作MyBatis
            //conf.xml -> reader
            Reader reader = Resources.getResourceAsReader("conf.xml") ;
            //reader  ->SqlSession
        
            //可以通过build的第二参数 指定数据库环境
            SqlSessionFactory sessionFacotry = new SqlSessionFactoryBuilder().build(reader,"development") ;
            SqlSession session = sessionFacotry.openSession() ;
        
            StudentMapper studentMapper = session.getMapper(StudentMapper.class) ;
            Student student = studentMapper.queryStudentByStunoWithConverter(1) ;//接口中的方法->SQL语句
        
          System.out.println(student);
            session.close();
        }
        
  • 实体类的属性和表中字段名不一致

    • 解决方案

      • 在Mapper.xml 的<resultMap>标签中配置字段的映射关系:
      <resultMap type="student" id="studentResult">
          <!-- 分为主键id 和非主键 result -->
          <id property="stuNo"  column="stuno"  />
          <result property="stuName"  column="stuname" />
          <result property="stuAge"  column="stuage" />
          <result property="graName"  column="graname" />
          <result property="stuSex"  column="stusex"  javaType="boolean" jdbcType="INTEGER"/>
      </resultMap>
      
      • 注意

        jdbcType="INTEGER",Integer要全大写。
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunnyboy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值