mybatis

源于动力节点mybatis,复习使用

文章目录

三层架构

  1. 界面层: 和用户打交道的, 接收用户的请求参数, 显示处理结果的。(jsp ,html ,servlet)
  2. 业务逻辑层: 接收了界面层传递的数据,计算逻辑,调用数据库,获取数据
  3. 数据访问层: 就是访问数据库, 执行对数据的查询,修改,删除等等的。
  • 三层对应的包
    界面层: controller包 (servlet)
    业务逻辑层: service 包(XXXService类)
    数据访问层: dao包(XXXDao类)

  • 三层中类的交互
    用户使用界面层–> 业务逻辑层—>数据访问层(持久层)–>数据库(mysql)

    ​ 用户在界面层发起请求,请求传递到业务逻辑层,业务逻辑层经过处理,通过持久层访问数据库拿到数据信息。业务逻辑 层处理加工信息,把执行结果通过界面层展示给用户。

  • 三层对应的处理框架
    界面层—servlet—springmvc(框架)
    业务逻辑层—service类–spring(框架)
    数据访问层—dao类–mybatis(框架)

框架的介绍

框架是一个软件,半成品的软件,定义好了一些基础功能, 需要加入你的功能就是完整的。
基础功能是可重复使用的,可升级的。

框架特点:

  1. 框架一般不是全能的, 不能做所有事情
  2. 框架是针对某一个领域有效。 特长在某一个方面,比如mybatis做数据库操作强,但是他不能做其它的。
  3. 框架是一个软件

mybatis框架的介绍

使用jdbc开发

public void findStudent() {
     Connection conn = null;
     Statement stmt = null;
     ResultSet rs = null;
     try {
         //注册 mysql 驱动
         Class.forName("com.mysql.jdbc.Driver");
         //连接数据的基本信息 url ,username,password
         String url = "jdbc:mysql://localhost:3306/springdb";
         String username = "root";
         String password = "123456";
         //创建连接对象
         conn = DriverManager.getConnection(url, username, password);
         //保存查询结果
         List<Student> stuList = new ArrayList<>();
         //创建 Statement, 用来执行 sql 语句
         stmt = conn.createStatement();
         //执行查询,创建记录集,
         rs = stmt.executeQuery("select * from student");
         while (rs.next()) {
         Student stu = new Student();
         stu.setId(rs.getInt("id"));
         stu.setName(rs.getString("name"));
         stu.setAge(rs.getInt("age"));
         //从数据库取出数据转为 Student 对象,封装到 List 集合
         stuList.add(stu);
         }
         } catch (Exception e) {
         e.printStackTrace();
         } finally {
         try {
         //关闭资源
         if (rs != null) ;
         {
            rs.close();
         }
         if (stmt != null) {
             stmt.close();
         }
         if (conn != null) {
            conn.close();
         }
         } catch (Exception e) {
            e.printStackTrace();
         }
     }
}

使用jdbc:

  1. 代码比较多,开发效率低
  2. 需要关注 Connection ,Statement, ResultSet 对象创建和销毁
  3. 对 ResultSet 查询的结果,需要自己封装为 List
  4. 重复的代码比较多些
  5. 业务代码和数据库的操作混在一起

mybatis框架的功能

一个框架,早期叫做ibatis, 代码在github。mybatis是 MyBatis SQL Mapper Framework for Java (sql映射框架)

  • sql mapper :sql映射
    可以把数据库表中的一行数据 映射为 一个java对象。
    一行数据可以看做是一个java对象。操作这个对象,就相当于操作表中的数据

  • Data Access Objects(DAOs) : 数据访问 , 对数据库执行增删改查。

mybatis提供了哪些功能:

  1. 提供了创建Connection ,Statement, ResultSet的能力 ,不用开发人员创建这些对象了
  2. 提供了执行sql语句的能力, 不用你执行sql
  3. 提供了循环sql, 把sql的结果转为java对象, List集合的能力
  4. 提供了关闭资源的能力,不需要关闭Connection, Statement, ResultSet

而开发人员做的是: 提供sql语句
最后是: 开发人员提供sql语句–mybatis处理sql—开发人员得到List集合或java对象(表中的数据)

总结:
mybatis是一个sql映射框架,提供的数据库的操作能力。增强版的JDBC

mybatis入门

创建表

CREATE TABLE `student` (
 `id` int(11) NOT NULL ,
 `name` varchar(255) DEFAULT NULL,
 `email` varchar(255) DEFAULT NULL,
 `age` int(11) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

输入数据:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uM16VgpR-1641562178727)(mybatis.assets/table_data.png)]

idea创建maven项目

创建一个空工程

在这里插入图片描述

在新工程下创建module:

在这里插入图片描述

新创建pom文件中build下,可以直接删除:(写不写都是依赖这些插件,默认给出了是方便用户自己配置)

在这里插入图片描述

加入maven坐标,依赖,插件

<?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>ysk</groupId>
  <artifactId>01-hello-mybatis</artifactId>
  <version>1.0-SNAPSHOT</version>


  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <!--mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
    <!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.9</version>
    </dependency>

  </dependencies>
<!--  资源插件:编译后会拷贝src/main/java文件夹下的非java文件到target/classes文件夹下-->
  <build>
    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
  </build>
</project>

类、接口、映射文件

  1. 实体类

    package ysk.domain;
    
    //类的名称建议和表名一样
    public class Student {
        //属性和列名一样
        private Integer id;
        private String name;
        private String email;
        private Integer age;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", email='" + email + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    
  2. 接口

    package ysk.dao;
    
    import ysk.domain.Student;
    
    import java.util.List;
    
    public interface StudentDao {
    	//查询所有学生信息
        public List<Student> selectStudents();
    }
    
    
  3. 编写 Dao 接口 Mapper 映射文件 StudentDao.xml

    • 在 dao 包中创建文件 StudentDao.xml
    • 要 StudentDao.xml 文件名称和接口 StudentDao 一样,区分大小写的一样

      在这里插入图片描述

StudentDao.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">
<mapper namespace="ysk.dao.StudentDao">
    <!--namespace:必须有值,自定义的唯一字符串
 推荐使用:dao 接口的全限定名称 -->

    <select id="selectStudents" resultType="ysk.domain.Student">
        <!--
              select:表示查询操作。
              id: 你要执行的sql语法的唯一标识, mybatis会使用这个id的值来找到要执行的sql语句
                  可以自定义,但是要求你使用接口中的方法名称。(简单的来说就是给这条sql语句起了个名字)
              resultType:表示结果类型的, 是sql语句执行后得到ResultSet,遍历这个ResultSet得到java对象的类型。
                 值写的类型的全限定名称(这条sql语句执行后的返回值)
           -->
        select id,name,email,age from student order by id
    </select>
</mapper>

sql映射文件(sql mapper): 写sql语句的, mybatis会执行这些sql
1.指定约束文件

<!DOCTYPE mapper
   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

mybatis-3-mapper.dtd是约束文件的名称, 扩展名是dtd的。

2.约束文件作用: 限制,检查在当前文件中出现的标签,属性必须符合mybatis的要求。

3.mapper 是当前文件的根标签,必须的。
namespace:叫做命名空间,唯一值的, 可以是自定义的字符串。
要求你使用dao接口的全限定名称。

4.在当前文件中,可以使用特定的标签,表示数据库的特定操作。

<select>:表示执行查询,select语句 <update>:表示更新数据库的操作, 就是在<update>标签中 写的是update sql语句 <insert>:表示插入, 放的是insert语句 <delete>:表示删除, 执行的delete语句

mybatis的主配置文件

项目 src/main 下创建 resources 目录,设置 resources 目录为 resources root 创建主配置文件:名称为 mybatis.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="mydev">
        <!-- environment : 一个数据库信息的配置, 环境
             id:一个唯一值,自定义,表示环境的名称。
			下面可以写多个environment,default控制用哪个
        -->
        <environment id="mydev">
            <!--
               transactionManager :mybatis的事务类型
                   type: JDBC(表示使用jdbc中的Connection对象的commit,rollback做事务处理)
            -->
            <transactionManager type="JDBC"/>
            <!--
               dataSource:表示数据源,连接数据库的
                  type:表示数据源的类型, POOLED表示使用连接池
            -->
            <dataSource type="POOLED">
                <!--
                   driver, user, username, password 是固定的,不能自定义。
                -->
                <!--数据库的驱动类名-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--连接数据库的url字符串-->
                <property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
                <!--访问数据库的用户名-->
                <property name="username" value="root"/>
                <!--密码-->
                <property name="password" value="123"/>
            </dataSource>
        </environment>
    </environments>

    <!-- sql mapper(sql映射文件)的位置-->
    <mappers>
         <!--一个mapper标签指定一个文件的位置。
           从类路径开始的路径信息。  target/clasess(类路径)
        -->
        <mapper resource="ysk/dao/StudentDao.xml"/>
        <!--<mapper resource="com/bjpowernode/dao/SchoolDao.xml" />-->
    </mappers>
</configuration>

测试

main目录下新建测试类:

clasess目录下面的文件才是程序执行时所需要的

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 ysk.domain.Student;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class Hello {
    public static void main(String[] args) throws IOException {
        //访问mybatis读取student数据
        //1.定义mybatis主配置文件的名称, 从类路径的根开始(target/clasess)
        //clasess目录下面的文件才是程序执行时所需要的
        String config="mybatis.xml";
        //2.读取这个config表示的文件
        InputStream in = Resources.getResourceAsStream(config);
        //3.创建了SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder builder  = new SqlSessionFactoryBuilder();
        //4.创建SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(in);
        //5.获取SqlSession对象,从SqlSessionFactory中获取SqlSession
        SqlSession sqlSession = factory.openSession();
        //6.【重要】指定要执行的sql语句的标识。  sql映射文件中的namespace + "." + 标签的id值
        //String sqlId = "com.bjpowernode.dao.StudentDao" + "." + "selectStudents";
        //namespace.id值为sqlId的执行语句

        String sqlId = "ysk.dao.StudentDao.selectStudents";
        //7. 重要】执行sql语句,通过sqlId找到要执行的sql语句
        List<Student> studentList = sqlSession.selectList(sqlId);
        //8.输出结果
        //studentList.forEach( stu -> System.out.println(stu));
        for(Student stu : studentList){
            System.out.println("查询的学生="+stu);
        }
        //9.关闭SqlSession对象
        sqlSession.close();
    }
}

读取成功:

在这里插入图片描述

出现问题几种解决方法

  1. 检查是否加入了资源插件
  2. 先 clean再compile
  3. 上方窗口中build的rebuild project
  4. 上方窗口中file的Invalidate Caches
  5. 手工拷贝复制target不存在的文件

配置日志功能

mybatis.xml 文件加入日志配置,可以在控制台输出执行的 sql 语句和参数

<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>

基本的增删改查

insert

  1. StudentDao接口中增加方法

    int insertStudent(Student student); //返回插入信息的条数
    
  2. sql映射文件

    插入的具体格式是 #{ },没有返回的实体类类型,所以不用resultType这个属性

    <insert id="insertStudent">
        insert into student(id,name,email,age) values(#{id},#{name},#{email},#{age})
    </insert>
    
  3. 测试类

    注意! 创建测试类的时候类名不要起名为 Test!

    不是自动提交事务,需要手动设置
    session.commit();

    package ysk;
    
    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 org.junit.Test;
    import ysk.domain.Student;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class TestMybatis {
        @Test
        public void testInsert() throws IOException {
            //1.mybatis 主配置文件
            String config = "mybatis.xml";
            //2.读取配置文件
            InputStream in = Resources.getResourceAsStream(config);
            //3.创建 SqlSessionFactory 对象
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
            //4.获取 SqlSession
            SqlSession session = factory.openSession();
            //5.创建保存数据的对象
            Student student = new Student();
            student.setId(1099);
            student.setName("张丽");
            student.setEmail("[email protected]");
            student.setAge(20);
            //6.执行插入 insert
            int rows = session.insert(
                    "ysk.dao.StudentDao.insertStudent",student);
            //7.不是自动提交事务,需要手动设置
            session.commit();
            System.out.println("增加记录的行数:"+rows);
            //8.关闭 SqlSession
            session.close();
        }
    }
    

    mybatis对象分析

对象使用

  1. Resources 类

    Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返 回不同类型的 IO 流对象。

  2. SqlSessionFactoryBuilder 类

    SqlSessionFactory 的 创 建 , 需 要 使 用 SqlSessionFactoryBuilder 对 象 的 build() 方 法 。 由 于 SqlSessionFactoryBuilder 对象在创建完工厂对象后,就完成了其历史使命,即可被销毁。所以,一般会将 该 SqlSessionFactoryBuilder 对象创建为一个方法内的局部对象,方法结束,对象销毁。

  3. SqlSessionFactory 接口

    SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用 只需要一个该对象即可。创建 SqlSession 需要使用 SqlSessionFactory 接口的的 openSession()方法。、

    • openSession(true):创建一个有自动提交功能的 SqlSession

    • openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交

    • openSession():同 openSession(false)

      从而,可以这样简化写法:

    //获取SqlSession对象,从SqlSessionFactory中获取SqlSession
    SqlSession sqlSession = factory.openSession();
    //mybatis默认不是自动提交事务的, 所以在insert ,update ,delete后要手工提交事务
    sqlSession.commit();
    
    //直接这样写也可以
    SqlSession sqlSession = factory.openSession(true);
    
  4. SqlSession 接口

    SqlSession 接口对象用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,一次会话以 SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束。 SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将 其关闭。再次需要会话,再次创建。 SqlSession 在方法内部创建,使用完毕后关闭。

编写工具类

package ysk.utils;

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 MyBatisUtils {
    private static SqlSessionFactory factory = null;

    static {
        String config = "mybatis.xml";
        try {
            InputStream in = Resources.getResourceAsStream(config);
            factory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //获取SqlSession的方法
    public static SqlSession getSqlSession() {
        SqlSession sqlSession = null;
        if (factory != null) {
            sqlSession = factory.openSession();// 非自动提交事务
        }
        return sqlSession;
    }

}

使用工具类

SqlSession session = MyBatisUtils.getSqlSession();
//5.创建保存数据的对象
Student student = new Student();
student.setId(1050);
student.setName("张丽");
student.setEmail("[email protected]");
student.setAge(20);
//6.执行插入 insert
int rows = session.insert(
    "ysk.dao.StudentDao.insertStudent",student);
//7.不是自动提交事务,需要手动设置
session.commit();
System.out.println("增加记录的行数:"+rows);
//8.关闭 SqlSession
session.close();

使用idea创建模板

  • 创建mapper文件模板

在这里插入图片描述

  • 创建主配置文件模板

    同上

传统 dao改进

StudentDao类几乎没有用到,主要还是用到了sqlsession的方法,StudentDao类主要是做一个指引的指示

  1. 定义接口以及实现类

    package ysk.dao.impl;
    
    import org.apache.ibatis.session.SqlSession;
    import ysk.dao.StudentDao;
    import ysk.dao.utils.MyBatisUtils;
    import ysk.domain.Student;
    
    import java.util.List;
    
    public class StudentDaoImpl implements StudentDao {
        @Override
        public List<Student> selectStudents() {
            SqlSession session = MyBatisUtils.getSqlSession();
            String sqlId = "ysk.dao.StudentDao.selectStudents";
            List<Student> stu = session.selectList(sqlId);
            //关闭
            session.close();
            return stu;
        }
    
        @Override
        public int insertStudent(Student student) {
            SqlSession session = MyBatisUtils.getSqlSession();
            String sqlId = "ysk.dao.StudentDao.insertStudent";
            int nums = session.insert(sqlId,student);
            session.commit();  //提交事务
            session.close(); //关闭
            return nums;
        }
    }
    
    
  2. mapper映射文件

    <?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">
    <mapper namespace="ysk.dao.StudentDao">
    
        <select id="selectStudents" resultType="ysk.domain.Student">
           select id,name,email,age from student order by id
        </select>
    
        <insert id="insertStudent">
            insert into student values(#{id},#{name},#{email},#{age})
        </insert>
    </mapper>
    

以上代码还是有大量重复冗余的代码,可以继续封装。

MyBatis 框架 Dao 代理

MyBatis 框架 Dao 代理

主要作用:干掉dao的实现类

只需调用 SqlSession 的 getMapper()方法,即可获取指定接口的实现类对象。该方法的参数为指定 Dao 接口类的 class 值。

mybatis根据 dao的方法调用,获取执行sql语句的信息
mybatis根据dao接口,创建dao接口的实现类, 并创建该类的对象,完成SqlSession调用方法, 访问数据库
具体如何创建如何执行:

使用mybatis的动态代理机制, 使用SqlSession.getMapper(dao接口),getMapper能获取dao接口对应的实现类对象
mybatis内部通过接口名和方法名映射到对应xml文件中的sql语句执行

注意:这里,接口中定义的方法名称和StudentDao.xml 中的id要保持一样。

具体代码:

package ysk;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import ysk.dao.StudentDao;

import ysk.dao.utils.MyBatisUtils;
import ysk.domain.Student;

import java.util.List;

public class TestMybatis {

    @Test
    public void testSelect(){
        SqlSession session = MyBatisUtils.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        List<Student> stu = dao.selectStudents();
        for (Student student : stu) {
            System.out.println(student);
        }
        session.close();
    }

    @Test
    public void testInsert(){
        SqlSession session = MyBatisUtils.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        Student student= new Student();
        student.setId(1071);
        student.setName("盾山");
        student.setEmail("[email protected]");
        student.setAge(1111);
        int nums = dao.insertStudent(student);
        session.commit(); //提交事务!!!
        session.close();
        System.out.println("nums="+nums);
    }
}

深入理解参数

parameterType

parameterType: 接口中方法参数的类型, 类型的完全限定名或别名。这个属性是可选的,一般不写。因为 MyBatis 可以推断出具体传入语句的参数,默认值为未设置(unset)。接口中方法的参数从 java 代码传入到 mapper 文件的 sql 语句。

<select id="selectStudentById" parameterType="java.lang.Integer" resultType="ysk.domain.Student">
    select id,name, email,age from student where id=${id}
</select>

MyBatis 传递参数

从 java 代码中把参数传递到 mapper.xml 文件。

一个简单参数

Dao 接口中方法的参数只有一个简单类型(java 基本类型和 String),占位符 #{ 任意字符 },和方法的参数名无关。

接口

Student selectStudentById(Integer id);

StudentDao.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">
<mapper namespace="ysk.dao.StudentDao">

    <select id="selectStudentById" resultType="ysk.domain.Student">
       select id,name,email,age from student where id=#{id}
    </select>

    <insert id="insertStudent">
        insert into student values(#{id},#{name},#{email},#{age})
    </insert>
</mapper>

测试

@Test
public void testSelect(){
    SqlSession session = MyBatisUtils.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
    Student student = dao.selectStudentById(1001);
    System.out.println(student);
    session.close();
}

使用#{}之后, mybatis执行sql是使用的jdbc中的PreparedStatement对象
由mybatis执行下面的代码:

//使用#{}之后, mybatis执行sql是使用的jdbc中的PreparedStatement对象
    由mybatis执行下面的代码:
    1. mybatis创建Connection , PreparedStatement对象
    String sql="select id,name, email,age from student where id=?";
	PreparedStatement pst = conn.preparedStatement(sql);
	pst.setInt(1,1001);

2. 执行sql封装为resultType="com.bjpowernode.domain.Student"这个对象
    ResultSet rs = ps.executeQuery();
	Student student = null;
	while(rs.next()){
        //从数据库取表的一行数据, 存到一个java对象属性中
        student = new Student();
        student.setId(rs.getInt("id));
        student.setName(rs.getString("name"));
        student.setEmail(rs.getString("email"));
        student.setAge(rs.getInt("age"));
    }
    return student;  //给了dao方法调用的返回值

多个参数-使用@Param

上述一个简单参数当然也能用param传参

当 Dao 接口方法多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名”), mapper 文件使用#{自定义参数名}。

接口:

List<Student> selectStudentMultiParam(@Param("myname") String name,@Param("myage")
                                         Integer age);

mapper文件:

<select id="selectStudentMultiParam" resultType="ysk.domain.Student">
    select id,name,email,age from student where name=#{myname} or age=#{myage}
</select>

测试:

@Test
public void testMultiParam(){
    SqlSession session = MyBatisUtils.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
    List<Student> list = dao.selectStudentMultiParam("刘备", 20);
    for (Student student : list) {
        System.out.println(student);
    }
    session.close();
}

多个参数-使用对象

接口:

List<Student> selectStudentMultiObject(QueryParam queryParam);

创建保存参数值的对象 QueryParam:

package ysk.dao.ov;

public class QueryParam {
    private String queryName;
    private int queryAge;
//get set
}

mapper文件:

<select id="selectStudentMultiObject" resultType="ysk.domain.Student">
    select id,name,email,age from student
    where name=#{queryName,javaType=string,jdbcType=VARCHAR}
    or age =#{queryAge,javaType=int,jdbcType=INTEGER}
</select>

上述情况用的较少,一般这样用:

<select id="selectStudentMultiObject" resultType="ysk.domain.Student">
    select id,name,email,age from student
    where name=#{queryName}
    or age =#{queryAge}
</select>

测试文件:

@Test
public void testMultiObject(){
    SqlSession session = MyBatisUtils.getSqlSession();
    StudentDao dao = session.getMapper(StudentDao.class);
    QueryParam queryParam = new QueryParam();
    queryParam.setQueryAge(20);
    queryParam.setQueryName("zhangsan");
    List<Student> list = dao.selectStudentMultiObject(queryParam);
    for (Student student : list) {
        System.out.println(student);
    }
    session.close();
}

注意:可以灵活一点,QueryParam可以不创建,直接用student类也可以

多个参数-按位置

不推荐使用!

参数位置从 0 开始, 引用参数语法 #{ arg 位置 } , 第一个参数是#{arg0}, 第二个是#{arg1} 注意:mybatis-3.3 版本和之前的版本使用#{0},#{1}方式, 从 mybatis3.4 开始使用#{arg0}方式。

接口:

List<Student> selectByNameAndAge(String name,int age);

mapper文件:

<select id="selectByNameAndAge" resultType="ysk.domain.Student">
    select id,name,email,age from student where name=#{arg0} or age =#{arg1}
</select>

测试文件:

//按位置参数
List<Student> stuList = dao.selectByNameAndAge("李四",20);
for (Student student : stuList) {
    System.out.println(student);
}

多个参数-使用 Map

不推荐使用!

Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。Map 集合使用 String的 key, Object 类型的值存储参数。 mapper 文件使用 # { key } 引用参数值。

接口:

List<Student> selectMultiMap(Map<String,Object> map);

mapper文件:

<select id="selectMultiMap" resultType="ysk.domain.Student">
    select id,name,email,age from student where name=#{myname} or age =#{myage}
</select>

测试:

@Test
public void testSelectMultiMap(){
    Map<String,Object> data = new HashMap<>();
    data.put("myname","李力");// #{myname}
    data.put("myage",20); // #{myage}
    List<Student> stuList = studentDao.selectMultiMap(data);
    stuList.forEach( stu -> System.out.println(stu));
}

# 和 $ 的区别

  •  select id,name, email,age from student where id = #{id}
    

    结果是:select id,name, email,age from student where id =?

  • $

     select id,name, email,age from student where id = ${id}
    

    结果是:select id,name, email,age from student where id =1001

两者的区别:

  1. #:占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替 sql 语句的“?”。这样做更安全(防止sql注入),更迅速,通常也是首选做法,
  2. $ :字符串替换,告诉 mybatis 使用 $包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的 内容连接起来。主要用在替换表名,列名,不同列排序等操作。

替换列名或表名时用$:

接口:

Student findByDiffField(@Param("col") String colunName,@Param("cval") Object value);

mapper文件:

<select id="findByDiffField" resultType="ysk.domain.Student">
    select * from student where ${col} = #{cval}
</select>

测试:

Student student1 = dao.findByDiffField("id",1002);
System.out.println("按 id 列查询:"+student1);
Student student2 = dao.findByDiffField("email","[email protected]");
System.out.println("按 email 列查询:"+student2);

封装mybatis输出结果

resultType

mybatis执行了sql语句,得到java对象
mybatis执行sql语句, 然后mybatis调用类的无参数构造方法,创建对象,mybatis把ResultSet指定列值付给同名的属性

mapper文件:

<select id="selectMultiPosition" resultType="ysk.domain.Student">
    select id,name, email,age from student
</select>

对应:

ResultSet rs = executeQuery(" select id,name, email,age from student" );
while(rs.next()){
    Student  student = new Student();
	student.setId(rs.getInt("id"));
	student.setName(rs.getString("name"))
}

框架的处理: 使用构造方法创建对象。调用 setXXX 给属性赋值。

Student student = new Student();

sql 语句列java 对象方法
idsetId( rs.getInt(“id”) )调用列名对应的 set 方法 id 列 — setId() name 列 — setName()
namesetName( rs.getString(“name”) )……
emailsetEmail( rs.getString(“email”) )……
agesetAge( rs.getInt(“age”) )……

注意:Dao 接口方法返回是集合类型,需要指定集合中的类型,不是集合本身。

在这里插入图片描述

别名

mybatis.xml配置文件中定义别名的配置

两种方式:

  1. 一个类型一个别名

    type:自定义类型的全限定名称

    alias: 别名

    <typeAliases>
        <typeAlias type="ysk.domain.Student" alias="stu" />
    </typeAliases>
    
  2. <package> name是包名, 这个包中的所有类,类名就是别名(类名不区分大小写)

    <typeAliases>
        <package name="ysk.domain"/>
        <package name="ysk.vo"/>
    </typeAliases>
    

比较推荐使用的还是全限定名称(ysk.domain.Student),第二种定义别名的方式不推荐使用,可能不同包中有相同的类名导致报错!

返回值是map类型:

有限制条件:只能最多返回一行记录。超过一行就是错误!

接口:

//定义方法返回Map
Map<Object,Object> selectMapById(Integer id);

mapper文件:

<!--返回Map
    1)列名是map的key, 列值是map的value
    2)只能最多返回一行记录。多余一行是错误
-->
<select id="selectMapById" resultType="java.util.HashMap">
    select id,name,email from student where id=#{stuid}
</select>

测试:

 Map<Object,Object> map = dao.selectMapById(1001);
    System.out.println("map=="+map);

resultMap,列名和属性名不一致的两种解决方式

列名和属性名不一样,第一种方式:

mapper 文件:

<!--定义resultMap
    id:自定义名称,表示你定义的这个resultMap
    type:java类型的全限定名称
-->
<resultMap id="studentMap" type="ysk.domain.Student">
    <!--列名和java属性的关系-->
    <!--注解列,使用id标签
        column :列名
        property:java类型的属性名
    -->
    <id column="id" property="id" />
    <!--非主键列,使用result-->
    <result column="name" property="name" />
    <result column="email" property="email" />
    <result column="age" property="age" />

</resultMap>
<select id="selectAllStudents" resultMap="studentMap">
    select id,name, email , age from student
</select>

测试:

List<Student> student = dao.selectStudents();
for (Student student1 : student) {
    System.out.println(student1);
}
session.close();

resultMap是比较常用的,数据库字段和实体类属性名不对应的经常使用。

第二种方式:

使用resultType的属性,之后再定义的时候通过数据库名 id查询 映射到实体类中的的结果 进行辨别

<!--列名和属性名不一样:第二种方式
   resultType的默认原则是 同名的列值赋值给同名的属性, 使用列别名(java对象的属性名)
-->
<select id="selectDiffColProperty" resultType="ysk.domain.MyStudent">
    select id as stuid ,name as stuname, email as stuemail , age stuage from student
</select>

模糊like

第一种方式,推荐使用

接口:

List<Student> selectStudentLikeOne(String name);

mapper文件:

<select id="selectStudentLikeOne" resultType="ysk.domain.Student">
    select id,name,email,age from student where name like #{name}
</select>

测试:

String name = "%尚%";
List<Student> student = dao.selectStudentLikeOne(name);
for (Student student1 : student) {
    System.out.println(student1);
}
session.close();

第二种方式:

接口:

List<Student> selectLikeTwo(String name);

mapper文件:

"%" #{name} "%"中间一定要带空格

<!--第二种方式:在mapper文件中拼接 like的内容-->
<select id="selectLikeTwo" resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where name  like "%" #{name} "%"
</select>

测试:

String name = "张";
List<Student> students = dao.selectLikeTwo(name);

for(Student stu: students){
    System.out.println("*******学生="+stu);
}
sqlSession.close();

动态sql

if结构

对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。 语法: sql 语句的部分

mapper文件:

<select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
    select id,name, age, email from student
    where 
    <if test="name !=null and name !='' ">
       name = #{name}
    </if>
    <if test="age > 0">
        or age > #{age}
    </if>
</select>

接口:

 List<Student> selectStudent(Student student);

mapper文件:

<resultMap id="studentMap" type="ysk.domain.Student">
    <id column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="email" property="email"/>
    <result column="age" property="age"/>
</resultMap>

<select id="selectStudent" resultMap="studentMap">
    select id,name,email,age from student where
    <if test="name != null and name !=''">
        name = #{name}
    </if>
    <if test="age > 20">
        age = #{age}
    </if>
</select>

这种写法可能会导致错误,当姓名不满足要求时,sql语句变成where or age>20,sql语法错误!可在where后面加上1=1 避免这种错误!

测试:

Student student  = new Student();
student.setName("李四");
student.setAge(18);
List<Student> list = dao.selectStudent(student);
for (Student student1 : list) {
    System.out.println(student1);
}
session.close();

where结构

语法:<where> 其他动态 sql </where>

mapper文件:

<select id="selectStudentWhere" resultType="ysk.domain.Student">
    select id,name, age, email from student
    <where>
        <if test="name !=null and name !='' ">
            name = #{name}
        </if>
        <if test="age > 0">
            or age > #{age}
        </if>
    </where>
</select>

至少有一个if条件成立时where标签才会起作用,当or或者and多余时会自动将它去掉!

foreach

语法:

<foreach collection="集合类型" open="开始的字符" close="结束的字符" 
item="集合中的成员" separator="集合成员之间的分隔符">
 #{item 的值}
</foreach>

遍历 List<简单类型>

接口:

List<Student> selectStudentForList(List<Integer> idList);

拼接sql测试:

List<Integer> list = new ArrayList<>();
list.add(1001);
list.add(1002);
list.add(1003);
String sql = "select * from student where id in ";
StringBuilder builder = new StringBuilder();
builder.append("(");
for (Integer integer : list) {
    builder.append(integer).append(",");
}
builder.deleteCharAt(builder.length()-1); //删除最后一个逗号
builder.append(")");
sql+=builder.toString();
System.out.println(sql); //select * from student where id in (1001,1002,1003)

mapper文件:

<select id="selectForeachOne" resultType="ysk.domain.Student">
    select id,name,email,age from student where id in
    <foreach collection="list" item="myid" open="("  close=")" separator=",">
        #{myid}
    </foreach>
</select>

测试文件:

List<Integer> list = new ArrayList<>();
list.add(1001);
list.add(1002);
list.add(1003);
List<Student> stu = dao.selectForeachOne(list);
for (Student student : stu) {
    System.out.println(student);
}

遍历 List<对象类型>

接口:

 List<Student> selectForeachTwo(List<Student> stulist);

mapper文件:

<select id="selectForeachTwo" resultType="ysk.domain.Student">
    select * from student where id in
    <foreach collection="list" item="stu" open="("  close=")" separator=",">
        #{stu.id}
    </foreach>
</select>

测试文件:

List<Student> list = new ArrayList<>();
        Student s1 = new Student();
        s1.setId(1002);
        s1.setName("lisi");
        list.add(s1);
        Student s2 = new Student();
        s1.setId(1001);;
        s1.setName("zs");
        list.add(s1);
        List<Student> list1 = dao.selectForeachTwo(list);
        for (Student student : list1) {
            System.out.println(student);
        }

代码片段

<sql/>标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使用该 SQL 片断,需要使用 <include/>子标签。该<sql/>标签可以定义 SQL 语句中的任何部分,所以<include/>子标签可以放在动态 SQL 的任何位置。

简而言之就是定义了之后在其它地方可以使用,达到代码的复用。

<!--创建 sql 片段 id:片段的自定义名称-->
<sql id="studentSql">
    select id,name,email,age from student
</sql>
<select id="selectStudentSqlFragment" 
        resultType="com.bjpowernode.domain.Student">
    <!-- 引用 sql 片段 -->
    <include refid="studentSql"/>
    <if test="list !=null and list.size > 0 ">
        where id in
        <foreach collection="list" open="(" close=")" 
                 item="stuobject" separator=",">
            #{stuobject.id}
        </foreach>
    </if>
</select>

mybatis配置文件

主配置文件

之前项目中使用的 mybatis.xml 是主配置文件。 主配置文件特点:

  1. 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"
    
  2. 根元素<configuration>

  3. 主要包含内容:

    • 定义别名
    • 数据源
    • mapper文件

dataSource 标签

Mybatis 中访问数据库,可以连接池技术,但它采用的是自己的连接池技术。在 Mybatis 的 mybatis.xml 配置文件中,通过<dataSource type=”pooled”>来实现 Mybatis 中连接池的配置。

dataSource 类型

Mybatis 将数据源分为三类:

  • UNPOOLED 不使用连接池的数据源
  • POOLED 使用连接池的数据源
  • JNDI 使用 JNDI 实现的数据源

其中 UNPOOLED ,POOLED 数据源实现了 javax.sq.DataSource 接口, JNDI 和前面两个实现方式不同,了解 可以。

dataSource 配置

在 MyBatis.xml 主配置文件,配置 dataSource:

<dataSource type="POOLED">
    <!--连接数据库的四个要素-->
    <property name="driver" value="com.mysql.jdbc.Driver"/>
    <property name="url" 
              value="jdbc:mysql://localhost:3306/ssm?charset=utf-8"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</dataSource>

MyBatis 在初始化时,根据的 type 属性来创建相应类型的的数据源 DataSource,即: type=”POOLED”:MyBatis 会创建 PooledDataSource 实例

type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例 type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用

使用数据库属性配置文件

为了方便对数据库连接的管理,DB 连接四要素数据一般都是存放在一个专门的属性文件中的。MyBatis 主配置文件需要从这个属性文件中读取这些数据

  1. 在 classpath 路径下,创建 properties 文件

    在 resources 目录创建 jdbc.properties 文件,文件名称自定义。

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/springdb
    jdbc.user=root
    jdbc.passwd=123
    
  2. 使用 properties 标签

    修改主配置文件,文件开始位置加入

    <?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="jdbc.properties" />
    
  3. 使用 key 指定值

    <environments default="mydev">
        <environment id="mydev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--使用 properties 文件: 语法 ${key}-->
                <!--数据库的驱动类名-->
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.user}"/>
                <property name="password" value="${jdbc.passwd}"/>
            </dataSource>
        </environment>
    </environments>
    

mappers(映射器)

  1. 指定多个mapper文件

    <!-- sql mapper(sql映射文件)的位置-->
    <mappers>
        <mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
        <mapper resource="com/bjpowernode/dao/OrderDao.xml" />
    </mappers>
    
  2. 使用包名

    注意:此种方法要求 Dao 接口名称和 mapper 映射文件名称相同,且在同一个目录中!

    这个包中所有xml文件一次都能加载给mybatis

    <!-- sql mapper(sql映射文件)的位置-->
    <mappers>
        <package name="com.bjpowernode.dao"/>
       <!-- <package name="com.bjpowernode.dao2"/>
        <package name="com.bjpowernode.dao3"/>-->
    </mappers>
    
    

PageHelper

分页功能

  1. maven坐标

    <!--PageHelper依赖-->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.1.10</version>
    </dependency>
    
  2. 加入 plugin 配置

    在<environments>之前加入

    <plugins>
     <plugin interceptor="com.github.pagehelper.PageInterceptor" />
    </plugins>
    
  3. PageHelper 对象

    测试方法:

    @Test
    public void testSelect() throws IOException {
       //加入PageHelper的方法,分页
        // pageNum: 第几页, 从1开始
        // pageSize: 一页中有多少行数据
        PageHelper.startPage(1,3);
        List<Student> studentList = studentDao.selectStudents();
        studentList.forEach( stu -> System.out.println(stu));
    }
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐