mybatis01-Lombok、mybatis原理、参数处理、模糊查询、结果封装

news2024/11/20 4:43:35

mybatis01

Lombok

一、Lombok的使用

  • Lombok 是一个Java库,能自动插入编辑器并构建工具,简化Java开发。
  • 通过加注解的方式,不需要为类编写getter、setter、constructor或equals,同时可以自动化日志变量。

第一步、在pom.xml中加载Lombok的jar包

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.etime</groupId>
    <artifactId>day0414</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <spring.version>5.2.5.RELEASE</spring.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>
    </dependencies>
</project>

第二步、安装Lombok

在这里插入图片描述

第三步、Lombok使用

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {

    private String id;
    private String name;
    private String gender;
    private Date birthday;
    private String s_class;
    private String photo;
}

第四步、Lombok测试

import com.etime.pojo.Student;

public class StudentTest {

    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setId("1");
        s1.setName("mary");
        System.out.println(s1);
        Student s2 = new Student("2","tom","男",null,"101",null);
        System.out.println(s2);
        
    }
}

// 结果
Student(id=1, name=mary, gender=null, birthday=null, s_class=null, photo=null)
Student(id=2, name=tom, gender=男, birthday=null, s_class=101, photo=null)

Process finished with exit code 0

二、Lombok常用注解

  1. @Setter
    • 位置:注解在类或字段
    • 使用:
      • 注解在类:为所有字段生成setter方法
      • 注解在字段:只为该字段生成setter方法
  2. @Getter
    • 位置:注解在类或字段
    • 使用:
      • 注解在类:为所有字段生成getter方法g
      • 注解在字段:只为该字段生成getter方法
  3. @ToString
    • 位置:注解在类
    • 使用:
      • 注解在类:添加toString方法
  4. @EqualsAndHashCode
    • 位置:注解在类
    • 使用:
      • 注解在类:生成hashCode和equals方法。
  5. @NoArgsConstructor
    • 位置:注解在类
    • 使用:
      • 注解在类:生成无参的构造方法。
  6. @RequiredArgsConstructor
    • 位置:注解在类
    • 使用:
      • 注解在类:为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。
  7. @AllArgsConstructor
    • 位置:注解在类
    • 使用:
      • 注解在类:生成包含类中所有字段的构造方法。
  8. @AllArgsConstructor
    • 位置:注解在类
    • 使用:
      • 注解在类:生成setter/getter、equals、canEqual、hashCode、toString方法,若为final属性,则不会为该属性生成setter方法。

Mybatis

一、Mybatis简介

二、Mybatis的基本使用方式

1、创建maven工程,引入依赖

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.16</version>
    </dependency>
    <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.47</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

2、编写实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {

    private String id;
    private String name;
    private String gender;
    private Date birthday;
    private String s_class;
    private String photo;
}

3、编写dao层接口

import com.etime.pojo.Student;

import java.util.List;

public interface StudentDao {
    // 查询所有学生信息
    List<Student> getAllStudents();
}

4、编写dao层的映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!--
引入dtd约束-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 是当前mapper对应的接口-->
<mapper namespace="com.etime.dao.StudentDao">
    <!--select:指定当前的操作为查询-->
    <!--id:当前标签对应的dao中 方法的名字-->
    <!--resultType:指定当前查询得到的数据要封装成的类型-->
    <select id="getAllStudents" resultType="com.etime.pojo.Student">
        select * from student
    </select>
</mapper>

5、编写核心配置文件mybatisConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--引入dtd约束-->
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--配置mybatis的环境-->
    <environments default="development">
        <!--配置环境-->
        <environment id="development">
            <!--配置事务的类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置链接数据库的信息:使用的是 数据源[连接池]-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/sms"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!--注册StudentDao接口映射文件位置-->
    <mappers>
        <mapper resource="mappper/StudentMapper.xml"></mapper>
    </mappers>
</configuration>

6、编写测试代码

@Test
public void test02() throws IOException {
    // 加载配置文件
    InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
    // 用于读取配置文件内容,生成SqlSessionFactory
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
    // 获取SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 获取StudentDao对象
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    List<Student> allStudents = studentDao.getAllStudents();
    System.out.println(allStudents);
    sqlSession.close();
}
// 结果
[Student(id=101, name=李淑玲, gender=, birthday=Tue Dec 28 00:00:00 CST 1999, s_class=1111, photo=2046184.jpg), Student(id=103, name=陆君, gender=, birthday=Mon Jun 03 00:00:00 CST 1974, s_class=95031, photo=2049659.jpg), Student(id=105, name=匡明, gender=, birthday=Thu Oct 02 00:00:00 CST 1975, s_class=95031, photo=2049660.jpg), Student(id=107, name=王丽, gender=, birthday=Fri Jan 23 00:00:00 CST 1976, s_class=95033, photo=2049673.jpg), Student(id=108, name=曾华, gender=, birthday=Thu Sep 01 00:00:00 CST 1977, s_class=95033, photo=2049675.jpg), Student(id=119, name=小母, gender=, birthday=Wed Mar 01 00:00:00 CST 2023, s_class=1111, photo=2050004.jpg), Student(id=120, name=欧吧胡, gender=, birthday=Tue Feb 14 00:00:00 CST 2023, s_class=1111, photo=2050010.jpg), Student(id=123, name=韩信, gender=, birthday=Thu Mar 09 00:00:00 CST 2023, s_class=1113, photo=2050143.jpg), Student(id=124, name=孙悟空, gender=, birthday=Thu Mar 02 00:00:00 CST 2023, s_class=1113, photo=2050230.jpg), Student(id=130, name=李白, gender=, birthday=Sat Mar 18 00:00:00 CST 2023, s_class=1111, photo=2051054.jpg), Student(id=190, name=娜可露露, gender=, birthday=Wed Jun 05 00:00:00 CST 2013, s_class=1111, photo=2051061.jpg), Student(id=191, name=露娜, gender=, birthday=Fri Mar 17 00:00:00 CST 2023, s_class=1111, photo=2050074.jpg)]

Process finished with exit code 0

7、项目结构

在这里插入图片描述

三、Mybatis原理

1、执行原理图

在这里插入图片描述

2、配置文件分析

(1)核心配置文件-核心配置文件参数详解
  1. environment标签的 id属性值 必须和 environments标签的default属性一致。

  2. 事务管理器

    • JDBC事务类型。直接使用了JDBC的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
    • MANAGED事务类型。从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。
     <transactionManager type="MANAGED">
           <property name="closeConnection" value="false"/>
        </transactionManager>
    
  3. 数据源 (DataSource)

    • 描述:dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。大多数 mybatis 应用程序会按示例中的例子来配置数据源、虽然数据眼配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。
    • 内建的数据源类型(type=“[UNPOOLED|POOLED|JNDI]”)
      • UNPOOLED
        • 这个数据源的实现会每次请求时打开和关闭连接。
        • 使用场景:虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。
      • POOLED
        • 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。
        • 这种处理方式很流行,能使并发 Web 应用快速响应请求。
      • JNDI
        • 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的数据源引用。
  4. mapper中的指定映射文件的位置的属性

    • 作用:指定映射文件的位置
    • resource
      • resource=“mapper/StudentMapper.xml”
      • 文件在多级目录中要用分隔符“/”隔开。
    • class
      • class=“com.etime.dao.StudentDao”
      • 指定StudentDao接口文件位置,但此时StudentDao.xml必须和接口处在同一个包中并且文件名要相同。
(2)映射文件-映射文件参数详解
  1. namespace必须为接口的完全限定名(即包名+类名的格式)。
  2. select标签中的id必须和接口中声明的方法同名。
  3. 如果接口中方法有返回值,resyultType必须跟方法返回值一致并采用返回值的完全限定名来表示。

3、底层源码分析

在这里插入图片描述

步骤解析

  1. 利用Resources.getResourceAsStream()方法读取核心配置文件,该配置文件中注册数据源(dataSource)和 映射文件(mappers标签中的mapper子标签的resource属性)

    • InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
      
  2. 展开映射文件(StudentMapper.xml)中定义的查询方法、查询时所封装结果类型和所要执行的sql语句。

    •  <select id="getAllStudents" resultType="com.etime.pojo.Student">
              select * from student
          </select>
      
  3. 使用 构建者模式 SqlSessionFactoryBuilder类的build方法创建SqlSessionFactory对象,在build方法中从字节输入流中解析数据。

    • SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
              SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
      
    • SqlSessionFactoryBuilder.java的build方法:

      • public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
          SqlSessionFactory var5;
          try {
              XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
              var5 = this.build(parser.parse());
          } catch (Exception var14) {
              throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
          } finally {
              ErrorContext.instance().reset();
        
              try {
                  inputStream.close();
              } catch (IOException var13) {
              }
        
          }
        
          return var5;
        }
        
    • XMLConfigBuilder的parse方法:

      • public Configuration parse() {
          if (this.parsed) {
              throw new BuilderException("Each XMLConfigBuilder can only be used once.");
          } else {
              this.parsed = true;
              this.parseConfiguration(this.parser.evalNode("/configuration"));
              return this.configuration;
          }
        }   
        
    • XMLConfigBuilder的parseConfiguration方法:

      • private void parseConfiguration(XNode root) {
          try {
              this.propertiesElement(root.evalNode("properties"));
              Properties settings = this.settingsAsProperties(root.evalNode("settings"));
              this.loadCustomVfs(settings);
              this.loadCustomLogImpl(settings);
              this.typeAliasesElement(root.evalNode("typeAliases"));
              this.pluginElement(root.evalNode("plugins"));
              this.objectFactoryElement(root.evalNode("objectFactory"));
              this.objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
              this.reflectorFactoryElement(root.evalNode("reflectorFactory"));
              this.settingsElement(settings);
              this.environmentsElement(root.evalNode("environments"));
              this.databaseIdProviderElement(root.evalNode("databaseIdProvider"));
              this.typeHandlerElement(root.evalNode("typeHandlers"));
              this.mapperElement(root.evalNode("mappers"));
          } catch (Exception var3) {
              throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3);
          }
        } 
        
    • XMLConfigBuilder的mapperElement方法:

      • private void mapperElement(XNode parent) throws Exception {
          if (parent != null) {
              Iterator var2 = parent.getChildren().iterator();
        
              while(true) {
                  while(var2.hasNext()) {
                      XNode child = (XNode)var2.next();
                      String resource;
                      if ("package".equals(child.getName())) {
                          resource = child.getStringAttribute("name");
                          this.configuration.addMappers(resource);
                      } else {
                          resource = child.getStringAttribute("resource");
                          String url = child.getStringAttribute("url");
                          String mapperClass = child.getStringAttribute("class");
                          XMLMapperBuilder mapperParser;
                          InputStream inputStream;
                          if (resource != null && url == null && mapperClass == null) {
                              ErrorContext.instance().resource(resource);
                              inputStream = Resources.getResourceAsStream(resource);
                              mapperParser = new XMLMapperBuilder(inputStream, this.configuration, resource, this.configuration.getSqlFragments());
                              mapperParser.parse();
                          } else if (resource == null && url != null && mapperClass == null) {
                              ErrorContext.instance().resource(url);
                              inputStream = Resources.getUrlAsStream(url);
                              mapperParser = new XMLMapperBuilder(inputStream, this.configuration, url, this.configuration.getSqlFragments());
                              mapperParser.parse();
                          } else {
                              if (resource != null || url != null || mapperClass == null) {
                                  throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
                              }
        
                              Class<?> mapperInterface = Resources.classForName(mapperClass);
                              this.configuration.addMapper(mapperInterface);
                          }
                      }
                  }
        
                  return;
              }    
        

    **总结:**上述代码中我们可以看到创建了一个XMLConfigBuilder对象用来解析XML,把配置文件中所有标签及标签中属性值放封装Configuration对象中并返回SqlSessionFactory对象。

  4. 调用SqlSessionFactory对象的openSession方法返回一个SqlSession对象,SqlSessionFactory是一个接口,我们找到它的实现类DefaultSqlSessionFactory类,点击它的openSession方法,打开openSessionFromDataSource方法。

    • SqlSession sqlSession = sqlSessionFactory.openSession();
      
    • DefaultSqlSessionFactory.java的openSessionFromDataSource方法:

      • private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
          Transaction tx = null;
        
          DefaultSqlSession var8;
          try {
              Environment environment = this.configuration.getEnvironment();
              TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
              //根据环境的配置创建一个新的事务
              tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
              Executor executor = this.configuration.newExecutor(tx, execType);
              //创建DefaultSqlSession对象,即SqlSession对象
              var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
          } catch (Exception var12) {
              this.closeTransaction(tx);
              throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
          } finally {
              ErrorContext.instance().reset();
          }
        
          return var8;
        }
        
  5. 调用sqlSession.getMapper(StudentDao.class)方法返回一个StudentDao接口的代理类对象。

    • StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
      
    • DefaultSqlSessionFactory.java的getMapper方法:

      • public <T> T getMapper(Class<T> type) {
          return this.configuration.getMapper(type, this);
        }
        
    • Configuration.java的getMapper方法:

      • public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
          return this.mapperRegistry.getMapper(type, sqlSession);
        }
        
    • MapperRegistry.java的getMapper方法:

      • public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
          MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
          if (mapperProxyFactory == null) {
              throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
          } else {
              try {
                  return mapperProxyFactory.newInstance(sqlSession);
              } catch (Exception var5) {
                  throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
              }
          }
        }
        
    • mapperProxyFactory.java的newInstance方法:

      • public T newInstance(SqlSession sqlSession) {
          MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
          return this.newInstance(mapperProxy);
        }
        

四、mybatis实现CRUD

1、在StudentDao接口中定义方法

import com.etime.pojo.Student;

import java.util.List;

public interface StudentDao {
    // 查询所有学生信息
    List<Student> getAllStudents();
    // 添加学生信息
    int addStudent(Student student);
    // 删除学生信息
    int deleteStudentById(String sid);
    // 修改学生信息
    int updateStudent(Student student);
    // 查询学生信息通过id
    Student getStudentById(String sid);
    // 统计学生总数
    int getContRows();
}

2、在映射文件中添加设置

<?xml version="1.0" encoding="UTF-8" ?>
<!--
引入dtd约束-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 是当前mapper对应的接口-->
<mapper namespace="com.etime.dao.StudentDao">
    <!--select:指定当前的操作为查询-->
    <!--id:当前标签对应的dao中 方法的名字-->
    <!--resultType:指定当前查询得到的数据要封装成的类型-->
    <select id="getAllStudents" resultType="com.etime.pojo.Student">
        select * from student
    </select>
   <!-- // 添加学生信息
    int addStudent(Student student);
    // 删除学生信息
    int deleteStudentById(int sid);
    // 修改学生信息
    int updateStudent(Student student);
    // 查询学生信息通过id
    Student getStudentById(int sid);
    // 统计学生总数
    int getContRows();-->
    <insert id="addStudent" parameterType="com.etime.pojo.Student">
        insert into student(id,name,gender,birthday,s_class,photo) values(#{id},#{name},#{gender},#{birthday},#{s_class},#{photo});
    </insert>
    <delete id="deleteStudentById" parameterType="String">
        delete from student where id=#{id};
    </delete>
    <update id="updateStudent" parameterType="com.etime.pojo.Student">
        update student set name=#{name},gender=#{gender},birthday=#{birthday},s_class=#{s_class},photo=#{photo} where id=#{id};
    </update>
    <select id="getStudentById" parameterType="String" resultType="com.etime.pojo.Student">
        select * from student where id=#{id};
    </select>
    <select id="getContRows" resultType="int">
        select count(*) from student;
    </select>
</mapper>

3、测试

@Test
public void test03() throws IOException {
    // 加载配置文件
    InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
    // 用于读取配置文件内容,生成SqlSessionFactory
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
    // 获取SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 获取StudentDao对象
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    Date date = Date.valueOf("2023-04-16");
    int res = studentDao.addStudent(new Student("11", "小李", "男", date, "1011", null));
    System.out.println("add res = " + res);
    sqlSession.commit();
    sqlSession.close();
}

@Test
public void test04() throws IOException {
    // 加载配置文件
    InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
    // 用于读取配置文件内容,生成SqlSessionFactory
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
    // 获取SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 获取StudentDao对象
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    int res = studentDao.deleteStudentById("11");
    System.out.println("delete res = " + res);
    sqlSession.commit();
    sqlSession.close();
}

@Test
public void test05() throws IOException {
    // 加载配置文件
    InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
    // 用于读取配置文件内容,生成SqlSessionFactory
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
    // 获取SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 获取StudentDao对象
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    Student student = new Student("11", "li", "男", null, "1011", null);
    int res = studentDao.updateStudent(student);
    System.out.println("update res = " + res);
    sqlSession.commit();
    sqlSession.close();
}

@Test
public void test06() throws IOException {
    // 加载配置文件
    InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
    // 用于读取配置文件内容,生成SqlSessionFactory
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
    // 获取SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 获取StudentDao对象
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    Student student = studentDao.getStudentById("11");
    System.out.println("student = " + student);
    sqlSession.close();
}

@Test
public void test07() throws IOException {
    // 加载配置文件
    InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
    // 用于读取配置文件内容,生成SqlSessionFactory
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
    // 获取SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 获取StudentDao对象
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    int contRows = studentDao.getContRows();
    System.out.println("contRows = "+ contRows);
    sqlSession.close();
}

4、提取工具类SqlSessionUtil.java

package com.etime.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 SqlSessionUtil {

    private static SqlSession sqlSession;

    static {
        InputStream in = null;
        try {
            // 加载配置文件
             in = Resources.getResourceAsStream("mybatisConfig.xml");
            // 用于读取配置文件内容,生成SqlSessionFactory
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
            // 获取SqlSession
            sqlSession = sqlSessionFactory.openSession();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

   public static SqlSession getSqlSession(){
        return sqlSession;
   }
}

5、测试工具类SqlSessionUtil

@Test
public void test02() throws IOException {

    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    // 获取StudentDao对象
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    List<Student> allStudents = studentDao.getAllStudents();
    System.out.println(allStudents);
    sqlSession.close();
}

五、mybatis的参数处理

1、parameterType 配置参数

(1)参数的使用说明
  • 作用:SQL语句传参,使用标签的 parameterType 属性来设定。
  • 参数类型 :基本类型,引用类型(例:String)、实体类类型(POJO 类)、实体类的包装类
(2)参数配置的注意事项
  • 基本类型和String:直接写类型名称 或 包名.类名的方式(例:java.lang.String)
  • 实体类类型:目前我们只能使用完全限定类名
    • 原因:是mybaits在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名,而我们的是实体类并没有注册别名,所以必须写全限定类名。
(3)mybatis 官方文档(参数)
别名映射的类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator

2、传递 pojo 包装对象

​ 开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括学生查询条件还包括其它的查询条件(比如将学生的老师也作为查询条件),这时可以使用包装对象传递输入参数,Pojo 类中包含 pojo。

(1)编写QueryVo
  • 学生类
package com.etime.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {

    private int id;
    private String name;
    private String gender;
    private Date birthday;
    private String s_class;
    private String photo;
}
  • 教师类
package com.etime.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Teacher {

    private int tid;
    private String tname;
}
  • QueryVo类
package com.etime.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class QueryVo {

    private Student student;
    private Teacher teacher;
}
(2)编写接口StudentDao方法
// 查询某个老师授课的男学生有哪些
List<Student> getStudentByQueryVo(QueryVo queryVo);
(3)编写持久层接口StudentMapper.xml
<select id="getStudentByQueryVo" parameterType="com.etime.pojo.QueryVo" resultType="com.etime.pojo.Student">
    select * from student s,teacher t,studentteacher st where s.sid=st.sid and t.tid=st.tid and t.tname=#{teacher.tname} and s.gender=#{student.gender}
</select>
(4)测试
@Test
public void test10(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    Student student = new Student(199, "李一111", "男", null, "1111", "li1.jpg");
    Teacher teacher = new Teacher(0,"jacy");
    QueryVo queryVo = new QueryVo(student,teacher);
    List<Student> list = studentDao.getStudentByQueryVo(queryVo);
    list.forEach(System.out::println);
    sqlSession.close();
}

3、map 集合数据作为参数的处理方式

(1)在接口StudentDao中添加方法 参数为 Map 集合
// 查询名字为"li李"的男生
List<Student> getStudentByGenderAndName(Map<String,Object> map);
(2)在映射文件 StudentMapper中 配置信息
<select id="getStudentByGenderAndName" parameterType="Map" resultType="com.etime.pojo.Student">
    select * from student where name=#{name} and gender=#{gender}
</select>
(3)测试
@Test
public void test11(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    Map<String,Object> map = new HashMap<>();
    map.put("name","li李");
    map.put("gender","男");
    List<Student> list = studentDao.getStudentByGenderAndName(map);
    list.forEach(System.out::println);
    sqlSession.close();
}

4、#{} 和 ${}的区别

#{}${}
预编译处理字符串替换
mybatis在处理#{},会将SQL中的#{}替换成?号,调用 PreparedStatement的set方法来赋值mybatis在处理 时,把 {}时,把 时,把{}替换成变量的值
使用#{}可以有效的防止SQL注入,提高系统安全性

六、mybatis模糊查询

  • 三种模糊查询方式

1、在接口StudentDao编写三种方法

/*
    模糊查询
 */
List<Student> getStudentByName1(String name);
List<Student> getStudentByName2(String name);
List<Student> getStudentByName3(String name);

2、在映射文件中编写对应SQL方法

(1)配置占位符方式-#{}
<select id="getStudentByName1" parameterType="String" resultType="com.etime.pojo.Student">
    select * from student where name like #{name}
</select>
(2)配置拼接字符串方式-${}
<!--将方式1的#{name},改成${name}。
注意:如果用模糊查询的这种方式,那么${name}的写法
就是固定的,不能写成其他名字-->
<select id="getStudentByName2" parameterType="String" resultType="com.etime.pojo.Student">
    select * from student where name like '%${name}%'
</select>
(3)配置MySQL函数方式-concat()
<select id="getStudentByName3" parameterType="String" resultType="com.etime.pojo.Student">
    select * from student where name like concat('%',#{name},'%')
</select>

3、模糊查询测试

@Test
public void test12(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    String name = "%李%";
    List<Student> list = studentDao.getStudentByName1(name);
    list.forEach(System.out::println);
    sqlSession.close();
}

@Test
public void test13(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    List<Student> list = studentDao.getStudentByName2("李");
    list.forEach(System.out::println);
    sqlSession.close();
}

@Test
public void test14(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    List<Student> list = studentDao.getStudentByName3("李");
    list.forEach(System.out::println);
    sqlSession.close();
}

七、mybatis结果封装

1、resultType结果类型

(1)resultType属性介绍
  • resultType 属性可以指定结果集的类型。
  • 支持基本类型和实体类类型。
  • 注意:
    • 它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。
    • 没有注册过的必须使用全限定类名。
    • 实体类中的属性名称必须和查询语句中的列名保持一致,否则无法实现封装。
2、resultType属性的使用
(1)基本类型

​ 前面的示例使用了,此处省略,去前面看。

(2)实体类型

​ 前面的示例使用了,此处省略,去前面看。

(3)特殊情况
  • ​ 情况:若修改Student类中的某个属性,例:sid改为stuId。
  • 分析:此时查询出的结果没有把表中的sid值映射到stuId属性中,因为属性和表中的列名不一致,内部无法用反射技术进行映射,所以为空。

a.实体类

package com.etime.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {

    private int stuId;
    private String name;
    private String gender;
    private Date birthday;
    private String s_class;
    private String photo;
}

b.修改映射文件StudentDao的SQL

  • 解决办法:修改映射配置,采用别名设置,让结果集中的列与实体类中的属性对应。
<select id="getAllStudents" resultType="Student">
    select id stuId,name,gender,birthday,s_class,photo from student;
</select>

c.测试

@Test
public void test01() throws IOException {
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    List<Student> allStudents = studentDao.getAllStudents();
    System.out.println(allStudents);
    allStudents.forEach(System.out::println);
    sqlSession.close();
}

2、resultMap自定义结果类型

(1)resultMap标签介绍
  • resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。
  • 实现封装
  • 在 select 标签中使用 resultMap 属性指定引用。
  • 同时 resultMap 可以实现将查询结果映射为复杂类型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。
(2)resultMap的使用
a.修改Student实体类,属性名与表不对应
package com.etime.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student {
    private int stuId;
    private String stuName;
    private String stuGender;
    private int stuAge;
    private String stuEmail;
    private String stuPhoto;
}
b.在接口StudentDao.java中编写方法
List<Student> getAllStudents();
c.在映射文件StudentDao.xml中编写SQL
 <select id="getAllStudents" resultMap="stuMap">
     select * from student
 </select>

 <resultMap id="stuMap" type="com.etime.pojo.Student">
     <id property="stuId" column="sid"></id>
     <result property="stuName" column="sname"></result>
     <result property="stuGender" column="sgender"></result>
     <result property="stuAge" column="sage"></result>
     <result property="stuEmail" column="semail"></result>
     <result property="stuPhoto" column="sphoto"></result>
 </resultMap>
d.测试
@Test
public void test01() throws IOException {
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    List<Student> allStudents = studentDao.getAllStudents();
    System.out.println(allStudents);
    allStudents.forEach(System.out::println);
    sqlSession.close();
}
e.resultType 和 resultMap
resultTyperesultMap
结果类型映射结果集与类中属性对应关系。
f.resultMap
标签描述
typeresultMap返回的类型
id指定主键字段
result指定非主键字段
column指定数据库列名
property指定实体类属性名称

type=“com.etime.pojo.Student”>







###### d.测试

```java
@Test
public void test01() throws IOException {
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
    List<Student> allStudents = studentDao.getAllStudents();
    System.out.println(allStudents);
    allStudents.forEach(System.out::println);
    sqlSession.close();
}
e.resultType 和 resultMap
resultTyperesultMap
结果类型映射结果集与类中属性对应关系。
f.resultMap
标签描述
typeresultMap返回的类型
id指定主键字段
result指定非主键字段
column指定数据库列名
property指定实体类属性名称

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/444520.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于动态车辆模型的百度Apollo LQR和MPC横向控制算法分析(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 Apollo 是由百度发起的一个高效、灵活的基于自动驾驶的测试和研发的平台。Apollo 的主要逻辑为局部规划 轨道跟踪。在局部规划…

4.1 插值概念与基础理论

学习目标&#xff1a; 学习插值的基础理论可以从以下几个方面入手&#xff1a; 理解插值的概念&#xff1a;插值是指根据已知数据点的函数值&#xff0c;构造出经过这些点的函数&#xff0c;用于在已知数据点之间估计函数值。可以将其看做是一种函数逼近的方法。 掌握插值多项…

【Linux】MySQL高可用之Mysql读写分离实践

一、MySQL读写分离原理 读写分离就是在主服务器上修改&#xff0c;数据会同步到从服务器&#xff0c;从服务器只能提供读取数据&#xff0c;不能写入&#xff0c;实现备份的同时也实现了数据库性能的优化&#xff0c;以及提升了服务器安全。 二、读写分离实践 绝大多数的企业的…

居家办公远程控制电脑怎么操作

居家办公或者混合办公&#xff0c;正成为一种新的流行趋势。如何更好地居家办公&#xff0c;实现更高的工作效率和更舒适办公体验&#xff0c;我们总结出如下建议。 无论您是每周远程工作几天还是全职工作&#xff0c;无论是出于选择还是因为健康状况或天气事件&#xff0c;都…

部署YUM仓库及NFS共享服务

一、YUM仓库服务 1&#xff09;YUM概述 YUM&#xff08;Yellow dog Updater Modified&#xff09; 基于RPM包构建的软件更新机制 可以自动解决依赖关系 所有软件包由集中的YUM软件仓库提供 linux本身就是以系统简洁为自身优势&#xff0c;所以在安装操作系统的时候并没有将…

Kaggle往期赛 | 多目标推荐系统大赛baseline

来源&#xff1a;深度之眼 作者&#xff1a;比赛教研部 编辑&#xff1a;学姐 Kaggle OTTO – Multi-Objective Recommender System多目标推荐系统大赛 赛题分析baseline 1、赛题链接 https://www.kaggle.com/competitions/otto-recommender-system/overview 2、赛题描述 本…

聚观早报 |字节与Meta争夺VR开发者;苹果设备无故要求输入ID密码

今日要闻&#xff1a;字节与Meta争夺VR应用开发者&#xff1b;苹果设备无故要求输入ID密码&#xff1b;余承东称25年是智能电动汽车分水岭&#xff1b;小鹏回应G6售价及配置信息曝光&#xff1b;亚马逊将在爱尔兰裁员200人 字节与Meta争夺VR应用开发者 4 月 14 日消息&#xf…

运筹说 第89期|网络计划-网络计划的优化

通过画网络图并计算时间参数&#xff0c;我们已得到了一个初步的网络计划&#xff0c;而网络计划技术的核心却在于从工期、成本、资源等方面对这个初步方案做进一步的改善和调整&#xff0c;以求得最佳效果&#xff0c;这一过程&#xff0c;就是网络计划的优化。接下来让我们跟…

家用洗地机到底好不好用?国产性价比高的品牌

洗地机作为一种高效、节能、环保、卫生的清洁设备&#xff0c;不仅能够提升清洁效率&#xff0c;还能有效减少清洁成本&#xff0c;更重要的是&#xff0c;它可以帮助我们创造一个更加健康和舒适的生活环境。而且除菌方面大部分都是采用电解水的除菌方式&#xff0c;更加环保和…

【我的创作纪念日—5周年】

序言 用心生活&#xff0c;用力向上&#xff0c;微笑前行&#xff0c;就是对生活最好的回馈。 机缘 最开始写文章&#xff0c;没想那么多&#xff0c;主要是记录一下&#xff0c;就随便写了下&#xff0c;后来认识了一些写文章的小伙伴&#xff0c;在和他们的沟通中越来越体会到…

PACS/RIS影像管理系统源码,采用VC++编程语言,提供三维图像后处理和算法

PACS/RIS影像管理系统源码 医学影像管理&#xff08;PACS/RIS&#xff09;系统是一套完整的提供DICOM标准遵从、高效的实现医学影像归档存储、通讯和诊断处理功能的医学影像信息管理系统&#xff0c;其基于DICOM/HL7标准的开放性架构和模块化的结构体系&#xff0c;确保了系统…

自动驾驶就是在扯?比亚迪你凭什么?

比亚迪“炮轰”自动驾驶 上周&#xff0c;在比亚迪2022年财报交流会上&#xff0c;有投资人问比亚迪在自动驾驶方面的发展进度和规划&#xff0c;比亚迪集团董事长王传福直言&#xff1a;“无人驾驶那都是扯淡&#xff0c;弄个虚头巴脑的东西那都是忽悠&#xff0c;它就是一场皇…

【超算/先进计算学习】日报4

目录 今日已完成任务列表遇到的问题及解决方案任务完成详细笔记高性能算法计算机算法的特征及内涵科学计算算法的主要分类高性能算法与传统算法的异同稀疏矩阵向量乘法 SpMV 与稀疏矩阵存储结构常见的稀疏矩阵传统存储与其SpMV算法不同的稀疏矩阵传统存储结构存储效率与稀疏度针…

Linux进程概念及状态

Linux进程概念及进程状态 目录 Linux进程概念及进程状态引入1、什么是进程1.1 描述进程1.2 task_struct组织进程1.3 proc目录 2、进程标识符3、查看进程4、bash进程5、初始fork6、进程状态6.1 操作系统层面6.2 Linux内核源代码RSDX 6.3 僵尸进程6.4 孤儿进程关于kill指令 引入 …

nssctf web 入门(9)

[SWPUCTF 2021 新生赛]sql [SWPUCTF 2021 新生赛]sql 可以猜测做了过滤 这里可以bp跑一下看过滤了哪些 尝试发现过滤了空格/**/在sql中代表注释符在mysql中这个可以用来代表空格 发现--被过滤 #也不行我们试下url编码的#也就是%23 成功了 3个字段 得到库名test_db 这里提示非…

一篇文章让你彻底学会--防抖(并且自己可以手写)

Hi,有的小伙伴们在面试的时候会被要求手写防抖函数&#xff0c;很多都被难着了吧&#xff0c;宝贝&#xff0c;那你你没有理解防抖函数。 今天&#xff0c;就让我带你攻克它&#xff01; 1.防抖 防抖:单位时间内&#xff0c;频繁触发事件&#xff0c;只执行最后一次。 人话:说…

嵌入式Linux(1):make menuconfig图形化界面

文章目录 搜索功能配置驱动状态退出和make menuconfig有关的三个文件make menuconfig会读取哪个目录下的Kconfig文件&#xff1f;为什么要复制成.config而不复制成其他的文件呢&#xff1f;在默认的deconfig上面通过make menuconfig来改配置&#xff0c;然后保存怎么和Makefile…

门店智能经营平台能解决哪些问题?应该如何选购?

现在很多实体店都开始借助第三方软件或系统&#xff0c;来为自家门店搭建门店智能经营平台&#xff0c;来智能管理自家门店的商品和库存&#xff0c;提高门店运营效率。 一、使用门店智能经营平台能解决哪些难题&#xff1f; 1、实现数据化决策 通过门店智能经营平台&#xff…

VUE3的使用

文章目录 一、Vue3基础语法1、Vue开发准备2、Vue的模板语法3、条件渲染4、列表渲染5、事件处理6、表单输入绑定 二、Components组件1、组件基础2、组件交互3、自定义事件的组件交互4、组件生命周期5、引入第三方组件 三、网络请求及路由配置1、Axios网络请求2、Axios网络请求封…

【Python_Matplotlib学习笔记(一)】pyplot模块的基本用法

pyplot模块的基本用法 前言 Matplotlib 是一个 Python 的 2D绘图库&#xff0c;它以各种硬拷贝格式和跨平台的交互式环境生成出版质量级别的图形&#xff08;来自&#xff1a;百度百科&#xff09;。pyplot 模块是 Matplotlib 模块提供的快速绘图模块&#xff0c;它模仿了 MA…