使用Mybatis这篇就够了

使用Mybatis这篇就够了,第1张

第一章 框架概述 1.1 三层架构

界面层: 和用户打交道的, 接收用户的请求参数, 显示处理结果的。


(jsp ,html ,servlet)
业务逻辑层: 接收了界面层传递的数据,计算逻辑,调用数据库,获取数据
数据访问层: 就是访问数据库, 执行对数据的查询,修改,删除等等的。


  1. 三层对应的包
  • 界面层: controller包 (servlet)
  • 业务逻辑层: service 包(XXXService类)
  • 数据访问层: dao包(XXXDao类)
  1. 三层中类的交互
  • 用户使用界面层–> 业务逻辑层—>数据访问层(持久层)–>数据库(mysql)
  1. 三层对应的处理框架
  • 界面层—servlet—springmvc(框架)

  • 业务逻辑层—service类–spring(框架)

  • 数据访问层—dao类–mybatis(框架)

1.2 框架

框架是一个舞台, 一个模版

1.2.1 模版
  1. 规定了好一些条款,内容。


  2. 加入自己的东西
1.2.2 框架是一个模块

​ 1.框架中定义好了一些功能。


这些功能是可用的。



​ 2.可以加入项目中自己的功能, 这些功能可以利用框架中写好的功能。


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



基础功能是可重复使用的,可升级的。


1.2.3 框架特点
  1. 框架一般不是全能的, 不能做所有事情
  2. 框架是针对某一个领域有效。


    特长在某一个方面,比如mybatis做数据库 *** 作强,但是他不能做其它的。


  3. 框架是一个软件
1.2.4 mybatis框架

mybatis框架,早期叫做ibatis, 代码在github。



mybatis是 MyBatis SQL Mapper Framework for Java (sql映射框架)
1)sql mapper :sql映射
可以把数据库表中的一行数据 映射为 一个java对象。



一行数据可以看做是一个java对象。


*** 作这个对象,就相当于 *** 作表中的数据

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


mybatis提供了哪些功能:

  1. 提供了创建Connection ,Statement, ResultSet的能力 ,不用开发人员创建这些对象了

  2. 提供了执行sql语句的能力, 不用你执行sql

  3. 提供了循环sql, 把sql的结果转为java对象, List集合的能力

    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);
      }
    
  4. 提供了关闭资源的能力,不用你关闭Connection, Statement, ResultSet

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

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

mybatis是一个sql映射框架,提供的数据库的 *** 作能力。


增强的JDBC,使用mybatis让开发人员集中精神写sql就可以了,不必关心Connection,Statement,ResultSet的创建,销毁,sql的执行。


第二章 快速入门

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gxdUVvTt-1648717794817)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220329210206197.png)]

2.1 实现步骤 2.1.1 创建student数据库表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g8CVNx60-1648717794819)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220329210359947.png)]

2.1.2加入maven的坐标和插件


<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.0modelVersion>

  <groupId>com.bjpowernodegroupId>
  <artifactId>ch01-hello-mybatisartifactId>
  <version>1.0-SNAPSHOTversion>
  
  <properties>
    <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    <maven.compiler.source>1.8maven.compiler.source>
    <maven.compiler.target>1.8maven.compiler.target>
  properties>

  <dependencies>
    <dependency>
      <groupId>junitgroupId>
      <artifactId>junitartifactId>
      <version>4.11version>
      <scope>testscope>
    dependency>
    
    <dependency>
      <groupId>org.mybatisgroupId>
      <artifactId>mybatisartifactId>
      <version>3.5.1version>
    dependency>
    
    <dependency>
      <groupId>mysqlgroupId>
      <artifactId>mysql-connector-javaartifactId>
      <version>5.1.9version>
    dependency>
  dependencies>

  <build>
    <resources>
      <resource>
        <directory>src/main/javadirectory>
        <includes>
          <include>**/*.propertiesinclude>
          <include>**/*.xmlinclude>
        includes>
        <filtering>falsefiltering>
      resource>
    resources>
  build>
project>

2.1.3创建实体类
package com.bjpowernode.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.1.4创建持久层dao接口
package com.bjpowernode.dao;

import com.bjpowernode.domain.Student;

import java.util.List;

//接口 *** 作student表
public interface StudentDao {

    //查询student表的所有的数据
    public List<Student> selectStudents();

    //插入方法
    //参数: student ,表示要插入到数据库的数据
    //返回值: int , 表示执行insert *** 作后的 影响数据库的行数
    public int insertStudent(Student student);
}
2.1.5创建mybatis的配置文件

叫做sql映射文件:写sql语句的。


一般一个表一个sql映射文件


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjpowernode.dao.StudentDao">
    
    <select id="selectStudents" resultType="com.bjpowernode.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>

2.1.6创建mybatis的主配置文件

一个项目就一个主配置文件。


主配置文件提供了数据库的连接信息和sql映射文件的位置信息。



DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

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

    
    <environments default="mydev">
        
        <environment id="mydev">
            
            <transactionManager type="JDBC"/>
            
            <dataSource type="POOLED">
                
                
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                
                <property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
                
                <property name="username" value="root"/>
                
                <property name="password" value="123456"/>
            dataSource>
        environment>


        
        <environment id="online">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/onlinedb"/>
                <property name="username" value="root"/>
                <property name="password" value="fhwertwr"/>
            dataSource>
        environment>
    environments>

    
    <mappers>
        
        <mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
        
    mappers>
configuration>

2.1.7创建测试类
package com.bjpowernode;

import com.bjpowernode.domain.Student;
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;
import java.util.List;

public class MyApp {

    public static void main(String[] args) throws IOException {
        //访问mybatis读取student数据
        //1.定义mybatis主配置文件的名称, 从类路径的根开始(target/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"; String sqlId = "com.bjpowernode.dao.StudentDao.selectStudents"; //7.【重要】执行sql语句,通过sqlId找到语句 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(); } }

2.1.8配置日志功能

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


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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qth5Fgrk-1648717794821)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220329211740321.png)]

2.2 主要类的介绍 2.2.1Resources:

​ mybatis中的一个类, 负责读取主配置文件
​ InputStream in = Resources.getResourceAsStream(“mybatis.xml”);

2.2.2SqlSessionFactoryBuilder :

创建SqlSessionFactory对象,

​ SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
​ //创建SqlSessionFactory对象
​ SqlSessionFactory factory = builder.build(in);

2.2.3SqlSessionFactory :

重量级对象, 程序创建一个对象耗时比较长,使用资源比较多。


在整个项目中,有一个就够用了。


SqlSessionFactory:接口 , 接口实现类: DefaultSqlSessionFactory
SqlSessionFactory作用: 获取SqlSession对象。


SqlSession sqlSession = factory.openSession();

openSession()方法说明:
1. openSession() :无参数的, 获取是非自动提交事务的SqlSession对象

  1. openSession(boolean): openSession(true) 获取自动提交事务的SqlSession.
    openSession(false) 非自动提交事务的SqlSession对象
2.2.4SqlSession:

SqlSession接口 :定义了 *** 作数据的方法 例如 selectOne() ,selectList() ,insert(),update(), delete(), commit(), rollback()
SqlSession接口的实现类DefaultSqlSession。


使用要求: SqlSession对象不是线程安全的,需要在方法内部使用, 在执行sql语句之前,使用openSession()获取SqlSession对象。



在执行完sql语句后,需要关闭它,执行SqlSession.close(). 这样能保证他的使用是线程安全的。


这里有一个问题,我们从始至终都没有用到Dao接口类,我们现在来用传统的Dao实现类来使用Dao接口

2.3mybatis使用传统dao开发方式 2.3.1创建持久层dao接口
package com.bjpowernode.dao;

import com.bjpowernode.domain.Student;

import java.util.List;

public interface StudentDao {

    List<Student> selectStudents();

    int insertStudent(Student student);
}
2.3.2创建dao接口实现类
package com.bjpowernode.dao.impl;

import com.bjpowernode.dao.StudentDao;
import com.bjpowernode.domain.Student;
import com.bjpowernode.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

public class StudentDaoImpl implements StudentDao {
    @Override
    public List<Student> selectStudents() {
        //获取SqlSession对象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        String sqlId="com.bjpowernode.dao.StudentDao.selectStudents";
        //执行sql语句, 使用SqlSession类的方法
        List<Student> students  = sqlSession.selectList(sqlId);
        //关闭
        sqlSession.close();
        return students;
    }
    @Override
    public int insertStudent(Student student) {
        //获取SqlSession对象
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        String sqlId="com.bjpowernode.dao.StudentDao.insertStudent";
        //执行sql语句, 使用SqlSession类的方法
        int nums = sqlSession.insert(sqlId,student);
        //提交事务
        sqlSession.commit();
        //关闭
        sqlSession.close();
        return nums;
    }
}
2.3.3测试类
package com.bjpowernode;

import com.bjpowernode.dao.StudentDao;
import com.bjpowernode.dao.impl.StudentDaoImpl;
import com.bjpowernode.domain.Student;
import org.junit.Test;

import java.util.List;

public class TestMyBatis {

    @Test
    public void testSelectStudents(){
        //com.bjpowernode.dao.StudentDao
        StudentDao dao  = new StudentDaoImpl();
        /**   实现原理:
         * List studentList  = dao.selectStudents(); 调用
         * 1.dao对象,类型是StudentDao,全限定名称是:com.bjpowernode.dao.StudentDao
         *   全限定名称 和 namespace 是一样的。


* * 2.方法名称, selectStudents, 这个方法就是 mapper文件中的 id值 selectStudents * * 3.通过dao中方法的返回值也可以确定MyBatis要调用的SqlSession的方法 * 如果返回值是List ,调用的是SqlSession.selectList()方法。


* 如果返回值 int ,或是非List的, 看mapper文件中的 标签是 就会调用 * SqlSession的insert, update等方法 * * mybatis的动态代理: mybatis根据 dao的方法调用,获取执行sql语句的信息。


* mybatis根据你的dao接口,创建出一个dao接口的实现类, 并创建这个类的对象。


* 完成SqlSession调用方法, 访问数据库。


* */ List<Student> studentList = dao.selectStudents(); for(Student stu:studentList){ System.out.println(stu); } } @Test public void testInsertStudent(){ StudentDao dao = new StudentDaoImpl(); Student student = new Student(); student.setId(1005); student.setName("盾山"); student.setEmail("[email protected]"); int nums = dao.insertStudent(student); System.out.println("添加对象的数量:"+nums); } }

2.2.4工具类
package com.bjpowernode.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);
            //创建SqlSessionFactory对象,使用SqlSessionFactoryBuild
            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;
    }
}
2.4 传统 Dao 开发方式的分析

​ 在前面例子中自定义 Dao 接口实现类时发现一个问题:Dao 的实现类其实并没有干什么实质性的工 作,它仅仅就是通过 SqlSession 的相关 API 定位到映射文件 mapper 中相应 id 的 SQL 语句,真正对 DB 进 行 *** 作的工作其实是由框架通过 mapper 中的 SQL 完成的。



​ 所以,MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句,对 DB 进行 *** 作。


这种对 Dao 的实现方式称为 Mapper 的动态代理方式。



​ Mapper 动态代理方式无需程序员实现 Dao 接口。


接口是由 MyBatis 结合映射文件自动生成的动态代 理实现的。


第三章 Mybatis框架Dao代理 3.1 实现方式 3.1.1去掉Dao接口实现类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FKiHu7id-1648717794822)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220329214821252.png)]

由于用到了动态代理,所以,我们不需要创建Dao的接口实现类,直接交给代理来生成Dao的接口实现类。


动态代理: 使用SqlSession.getMapper(dao接口.class) 获取这个dao接口的对象

3.1.2 getMapper获取代理对象
package com.bjpowernode;

import com.bjpowernode.dao.StudentDao;
import com.bjpowernode.domain.Student;
import com.bjpowernode.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;

import java.util.List;

public class TestMyBatis {

    @Test
    public void testSelectStudents(){
        /**
         * 使用mybatis的动态代理机制, 使用SqlSession.getMapper(dao接口)
         * getMapper能获取dao接口对于的实现类对象。


*/ SqlSession sqlSession = MyBatisUtils.getSqlSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class); //com.sun.proxy.$Proxy2 : jdk的动态代理 System.out.println("dao="+dao.getClass().getName()); //调用dao的方法, 执行数据库的 *** 作 List<Student> students = dao.selectStudents(); for(Student stu: students){ System.out.println("学生="+stu); } } @Test public void testInsertStudent(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); StudentDao dao = sqlSession.getMapper(StudentDao.class); Student student = new Student(); student.setId(1007); student.setName("李飞"); student.setEmail("[email protected]"); student.setAge(28); int nums = dao.insertStudent(student); sqlSession.commit(); System.out.println("添加对象的数量:"+nums); } }

3.2 深入理解参数 3.2.1 parameterType

parameterType : dao接口中方法参数的数据类型。


parameterType它的值是java的数据类型全限定名称或者是mybatis定义的别名
例如:parameterType=“java.lang.Integer”
parameterType=“int”

intjava.lang.Integer 
	 hashmap 或 java.util.HashMap 
	 list 或 java.util.ArrayList 
	 student 或 com.bjpowernode.domain.Student

注意:默认值为未设置(unset)。


接口中方法的参数从 java 代码传入到 mapper 文件的 sql 语句。



parameterType不是强制的,mybatis通过反射机制能够发 现接口参数的数类型。


所以可以没有。


一般我们也不写。


当传递的参数只有一个的时候:多个则不能使用这个属性

<select id="selectStudentById" parameterType="int" resultType="com.bjpowernode.domain.Student">
    select id,name, email,age from student where id=${studentId}
select>
3.2.2 MyBatis 传递参数 1.一个简单参数

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


与传入的对象无关,与传入的值有关。


单个参数传递给sql语句时不需要用命名参数,否则就需要使用命名参数。


接口:

/**
 * 一个简单类型的参数:
 *   简单类型: mybatis把java的基本数据类型和String都叫简单类型。


* 在mapper文件获取简单类型的一个参数的值,使用 #{任意字符} */ public Student selectStudentById(@Param("studentId") Integer id);

mapper:

<select id="selectStudentById" resultType="com.bjpowernode.domain.Student">
    select id,name, email,age from student where id=#{studentId}
select>
#{studentId} , studentId 是自定义的变量名称,和方法参数名无关。


2.多个参数-使用@Param

当 Dao 接口方法多个参数,需要通过名称使用参数。


在方法形参前面加入@Param(“自定义参数名”), mapper 文件使用#{自定义参数名}。


接口:

/**
 * 多个参数: 命名参数,在形参定义的前面加入 @Param("自定义参数名称")
 */
List<Student> selectMultiParam(@Param("myname") String name,
                               @Param("myage") Integer age);

mapper:


<select id="selectMultiParam" resultType="com.bjpowernode.domain.Student">
     select id,name, email,age from student where name=#{myname} or age=#{myage}
select>
3.多个参数-使用对象
  • vo: value object , 放一些存储数据的类。


    比如说 提交请求参数, name ,age 现在想把name ,age 传给一个service 类。


  • vo: view object , 从servlet把数据返回给浏览器使用的类,表示显示结果的类。


  • pojo: 普通的有set, get方法的java类。


    普通的java对象

     Servlet --- StudentService( addStudent( MyParam  param)  )
    
  • entity(domain域): 实体类, 和数据库中的表对应的类,

多个参数, 使用java对象的属性值,作为参数实际值
使用对象语法: #{属性名,javaType=类型名称,jdbcType=数据类型} 很少用。



javaType:指java中的属性数据类型。



jdbcType:在数据库中的数据类型。


例如: #{paramName,javaType=java.lang.String,jdbcType=VARCHAR}

我们使用常用的的简化方式:#{属性名} ,javaType, jdbcType的值mybatis反射能获取。


不用提供。


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KbqZTtdA-1648717794825)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220329225921187.png)]

接口:

/**
 * 多个参数,使用java对象作为接口中方法的参数
 */
List<Student> selectMultiObject(QueryParam param);

mapper:

<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
       select id,name, email,age from student where
        name=#{paramName,javaType=java.lang.String,jdbcType=VARCHAR}
        or age=#{paramAge,javaType=java.lang.Integer,jdbcType=INTEGER}
 select>

<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
          select id,name, email,age from student where
           name=#{paramName}   or age=#{paramAge}
select>
4.多个参数-按位置

参数位置从 0 开始, 引用参数语法 #{ arg 位置 } , 第一个参数是#{arg0}, 第二个是#{arg1}

接口:

/**
 * 多个参数-简单类型的,按位置传值,
 * mybatis.3.4之前,使用 #{0} ,#{1}
 * mybatis。


3.4之后 ,使用 #{arg0} ,#{arg1} */ List<Student> selectMultiPosition( String name,Integer age);

mapper:


<select id="selectMultiPosition" resultType="com.bjpowernode.domain.Student">
      select id,name, email,age from student where
      name = #{arg0} or age=#{arg1}
select>
5.多个参数-使用Map

Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。


Map 集合使用 String的 key, Object 类型的值存储参数。


mapper 文件使用 # { key } 引用参数值。


接口:

/**
 * 多个参数,使用Map存放多个值
 */
List<Student> selectMultiByMap(Map<String,Object> map);

mapper:


<select id="selectMultiByMap" resultType="com.bjpowernode.domain.Student">
      select id,name, email,age from student where
      name = #{myname} or age=#{age1}
select>
6.#和$

#:占位符,告诉 mybatis 使用实际的参数值代替。


并使用 PrepareStatement 对象执行 sql 语句, #{…}代替 sql 语句的“?”。


这样做更安全可以防止sql注入,更迅速,通常也是首选做法。


$ 字符串替换,告诉 mybatis 使用 包 含 的 “ 字 符 串 ” 替 换 所 在 位 置 。


使 用 S t a t e m e n t 把 s q l 语 句 和 包含的“字符串”替换所在位置。


使用 Statement 把 sql 语句和


使Statementsql{}的 内容连接起来。


主要用在:替换表名,列名,不同列排序等 *** 作。


可以替换表名或者列名, 你能确定数据是安全的。



<select id="selectUse$" resultType="com.bjpowernode.domain.Student">
     select * from student where name=${myname}
select>
<!--使用 #{}-->
<select id="selectUse" resultType="com.bjpowernode.domain.Student">
     select * from student where name=#{myname}
</select>
在日志中看到select语句是有?占位符出现的,这就说明,mybatis底层是调用执行对象preparedStatement对象。


实际上一个#{}就是对应着在底层的JDBC中的一个?号占位符 转为 MyBatis 的执行是: String sql=” select id,name,email,age from student where id=?; PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1,1005);

  select id,name, email,age from student where id=#{studentId}
  # 的结果: select id,name, email,age from student where id=? 
  
  // String sql="select id,name, email,age from student where id=" + "1001";
  // 使用的Statement对象执行sql, 效率比PreparedStatement低。


select id,name, email,age from student where id=${studentId} $ 的结果:select id,name, email,age from student where id=1001

#和 $区别
  1. #使用 ?在sql语句中做站位的, 使用PreparedStatement执行sql,效率高
  2. #能够避免sql注入,更安全。


3. $不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低 4. $有sql注入的风险,缺乏安全性。


5. $:可以替换表名或者列名

3.2.3 别名的定义

定义自定义类型的别名

  1. 在mybatis主配置文件中定义,使定义别名
  2. 可以在resultType中使用自定义别名

定义在mybatis主配置文件当中:


    <typeAliases>
        
        <typeAlias type="com.bjpowernode.domain.Student" alias="stu" />
        <typeAlias type="com.bjpowernode.vo.ViewStudent" alias="vstu" />
    typeAliases>
  <typeAliases>
		
  
        <package name="com.bjpowernode.domain"/>
        <package name="com.bjpowernode.vo"/>
  typeAliases>
3.3 封装Mybatis的输出结果 3.3.1 resultType

resultType结果类型, 指sql语句执行完毕后, 数据转为的java对象, java类型是任意的。


resultType结果类型的它值 1. 类型的全限定名称 2. 类型的别名。


例如 java.lang.Integer别名是int。


处理方式:
1. mybatis执行sql语句, 然后mybatis调用类的无参数构造方法,创建对象。



2. mybatis把ResultSet指定列值付给同名的属性。


	

	  对等的jdbc
	  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"))
	  }

resultType: 执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。


注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。


resultType 和 resultMap,不能同时使用。


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EwkfdDys-1648717794827)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220330213158335.png)]

可以把resultType里面的值,可以看做是接口中方法的返回值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-88vXlepi-1648717794828)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220330155940294.png)]

1.简单类型

接口:int countStudent();

mapper:



<select id="countStudent" resultType="java.lang.Integer">
    select count(*) from student
select>
2.对象类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fHoXwUL8-1648717794829)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220330160233384.png)]

接口:

ViewStudent selectViewStudent(int id);

mapper:


<select id="selectViewStudent" resultType="com.gz.vo.ViewStudent" >
    select id,name,email,age from student where id=#{id}
select>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LzHw6uNx-1648717794830)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220330214240452.png)]

3.Map

sql 的查询结果作为 Map 的 key 和 value。


推荐使用 Map。


注意:Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。


大于一条记录是错误。


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

<select id="selectMapById" resultType="java.util.HashMap">
    select id,name,email from student where id=#{stuid}
select>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0j3PqWPK-1648717794832)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220330214507029.png)]

3.3.2 resultMap

resultMap:结果映射, 指定列名和java对象的属性对应关系。



1)你自定义列值赋值给哪个属性
2)当你的列名和属性名不一样时,一定使用resultMap

​ resultMap和resultType不要一起用,二选一

resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。


更灵活的把列值赋值给指定属性。


常用在列名和 java 对象属性名不一样的情况。


使用方式: 1.先定义 resultMap,指定列名和属性的对应关系。


​ 2.在中把 resultType 替换为 resultMap。


接口:

/*
*  使用resultMap定义映射关系
* */
List<Student> selectAllStudents();

mapper:




<resultMap id="studentMap" type="com.bjpowernode.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="selectAllStudents" resultMap="studentMap">
    select id,name, email , age from student
select>

当数据库列名和 java 对象属性名不一样的情况下:

<resultMap id="myStudentMap" type="com.bjpowernode.domain.MyStudent">
    

    <id column="id" property="stuid" />
    
    <result column="name" property="stuname" />
    <result column="email" property="stuemail" />
    <result column="age" property="stuage" />

resultMap>

<select id="selectMyStudent" resultMap="myStudentMap">

     select id,name, email , age from student
select>
3.3.3 实体类属性名和列名不同的处理方式

步骤:

创建新的实体类 PrimaryStuden

package com.gz.entity;

public class PrimaryStudent {
    private Integer stuid;
    private String stuname;

    public PrimaryStudent() {
    }

    @Override
    public String toString() {
        return "PrimaryStudent{" +
                "stuid=" + stuid +
                ", stuname='" + stuname + '\'' +
                '}';
    }

    public Integer getStuid() {
        return stuid;
    }

    public void setStuid(Integer stuid) {
        this.stuid = stuid;
    }

    public String getStuname() {
        return stuname;
    }

    public void setStuname(String stuname) {
        this.stuname = stuname;
    }
}
1.使用列别名和resultType

接口方法

List<MyStudent> selectMyStudent();

mapper


    <resultMap id="studentMap" type="Student">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="email" property="email"/>
        <result column="age" property="age"/>
    resultMap>
    <select id="studentResultMap" resultMap="studentMap">
        select id,name,email,age from student where id = #{id}
    select>
2.使用resultMap

<select id="studentResultType" resultType="com.gz.entity.PrimaryStudent">
    select id as stuid,name as stuname,email,age from student where id = #{id}
select>


<resultMap id="studentMap1" type="com.gz.entity.PrimaryStudent">
    <id column="id" property="stuid"/>
    <result column="name" property="stuname"/>
resultMap>
3.使用数据库别名的方式

<select id="studentResultType" resultType="com.gz.entity.PrimaryStudent">
    select id as stuid,name as stuname,email,age from student where id = #{id}
select>
3.4 模糊like

模糊查询的实现有两种方式:一是 java 代码中给查询数据加上“%” ;

​ 二是在 mapper 文件 sql 语句的条件位置加上“%”。


1.java 代码中提供要查询的 “%xxx%”

mapper


<select id="selectLikeOne" resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where name like #{name}
select>

测试类

@Test
public void testSelectLikeOne(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);

    //准备好like的内容
    String name = "%李%";
    List<Student> students = dao.selectLikeOne(name);

    for(Student stu: students){
        System.out.println("#######学生="+stu);
    }
    sqlSession.close();
}
2.mapper 文件中使用 “%” #{xxx} “%”

mapper


<select id="selectLikeTwo" resultType="com.bjpowernode.domain.Student">
    select id,name,email,age from student where name  like "%" #{name} "%"
select>

测试类

@Test
public void testSelectLikeTwo(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    StudentDao dao = sqlSession.getMapper(StudentDao.class);

    //准备好like的内容
    String name = "张";
    List<Student> students = dao.selectLikeTwo(name);

    for(Student stu: students){
        System.out.println("*******学生="+stu);
    }
    sqlSession.close();
}
第四章 动态SQL

动态SQL: SQL的内容是变化的,可以根据条件获取到不同的sql语句。



主要是where部分发生变化。


动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行 查询。


提交的查询条件不同,执行的 SQL 语句不同。


若将每种可能的情况均逐一列出,对所有条件进行 排列组合,将会出现大量的 SQL 语句。


此时,可使用动态 SQL 来解决这样的问题。


4.1 注意事项
  • 在 mapper 的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等 符号,最好将其转换为实体符号。


    否则,XML 可能会出现解析出错问题。


  • 在使用动态SQL的使用,接口接收的参数一定要使用对象的方式。


特别是对于小于号(<),在 XML 中是绝不能出现的。


否则解析 mapper 文件会出错。


所以我们要使用实体符号:

<小于& lt;
>大于& gt;
>=大于等于& gt;=
<=小于等于& lt;=
4.2动态SQL之< if >

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


语法:< if test=“条件”> sql 语句的部分

接口:

//动态sql ,使用java对象作为参数
List<Student> selectStudentIf(Student student);

mapper:


<select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
    select id,name, age, email from student
    where id > 0
    <if test="name !=null and name !='' ">
       and name = #{name}
    if>
    <if test="age > 0">
        or age > #{age}
    if>
select>
4.3动态SQL之< where >
  • < if >标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句。


    因为,若 where 后 的所有条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,SQL 出错。


    所以,在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生。


    但当数据量很大时,会 严重影响查询效率。


  • 使用标签< where />,在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加 where 子句。


    需要注意的是,第一个< if />标签中的 SQL 片断,可以不包含 and。


    不过,写上 and 也不错, 系统会将多出的 and 去掉。


    但其它< if />>中 SQL 片断的 and,必须要求写上。


    否则 SQL 语句将拼接出错。


  • 语法:< where >其他动态SQL< where />


<select id="selectStudentWhere" resultType="com.bjpowernode.domain.Student">
    <include refid="studentSql" />
    <where>
        <if test="name !=null and name !='' ">
            name = #{name}
        if>
        <if test="age > 0">
            or age > #{age}
        if>
    where>
select>
4.4动态SQL之< foreach >

引入:当我们需要动态的给in命令里面添加参数时,我们要这样做

@Test
public void testfor(){
    List<Integer> list = new ArrayList<>();
    list.add(1001);
    list.add(1002);
    list.add(1003);

    //String sql="select * from student where id in (1001,1002,1003)";
    String sql="select * from student where id in";

    StringBuilder builder  = new StringBuilder("");
    int init=0;
    int len = list.size();

    //添加开始的 (
    builder.append("(");
    for(Integer i:list){
        builder.append(i).append(",");
    }
    builder.deleteCharAt(builder.length()-1);
    //循环结尾
    builder.append(")");
    sql = sql  + builder.toString();
    System.out.println("sql=="+sql);
}

特别的麻烦,所以我们有了< foreach >标签

在foreach中可以放循环的对象,也可以自定义小括号,用法灵活

  • 标签用于实现对于数组与集合的遍历。


    主要用在sql的in语句中。


    对其使用,需要注意:

➢ collection 表示要遍历的集合类型, list ,array 等。


➢ open、close、separator 为对遍历内容的 SQL 拼接。


  • 具体含义:

​ collection:表示接口中的方法参数的类型, 如果是数组使用array , 如果是list集合使用list
​ item:自定义的,表示数组和集合成员的变量
​ open:循环开始是的字符
​ close:循环结束时的字符
​ separator:集合成员之间的分隔符

  • 对应关系:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MhwesW6o-1648717794833)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220331105311586.png)]

第一种用法:遍历 List<简单类型>

接口:

//foreach 用法 1
List<Student> selectForeachOne(List<Integer> idlist);

mapper:

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

测试:

@Test
public void testSelectForEach(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    StudentDao dao  =  sqlSession.getMapper(StudentDao.class);

    List<Integer> list = new ArrayList<>();
    list.add(1001);
    list.add(1002);
    list.add(1003);

    List<Student> students = dao.selectForeachOne(list);
    for(Student stu:students){
        System.out.println("foreach--one ==="+stu);
    }
}
第二种用法:遍历 List<对象类型>

接口:

//foreach 用法 2
List<Student> selectForeachTwo(List<Student> stulist);

mapper:

<select id="selectForeachTwo" resultType="com.bjpowernode.domain.Student">
    select * from student where id in (
    <foreach collection="list" item="stu" >
        #{stu.id},
    foreach>
    -1 )
select>

测试:

@Test
public void testSelectForTwo(){
    SqlSession sqlSession = MyBatisUtils.getSqlSession();
    StudentDao dao  =  sqlSession.getMapper(StudentDao.class);

    List<Student> stuList  = new ArrayList<>();
    Student s1 = new Student();
    s1.setId(1002);
    s1.setName("lisi");
    stuList.add(s1);

    s1 = new Student();
    s1.setId(1005);;
    s1.setName("zs");
    stuList.add(s1);

    List<Student> students = dao.selectForeachTwo(stuList);
    for(Student stu:students){
        System.out.println("foreach--two ==="+stu);
    }
}
4.5动态SQL之< sql >

< sql />标签用于定义 SQL 片断,以便其它 SQL 标签复用。


而其它标签使用该 SQL 片断,需要使用< include />子标签。


该< sql />标签可以定义 SQL 语句中的任何部分,所以< include />子标签可以放在SQL的任何位置。



<sql id="studentSql">
    select id,name, age, email from student
sql>

<select id="selectStudentWhere" resultType="com.bjpowernode.domain.Student">
    <include refid="studentSql" />
    <where>
        <if test="name !=null and name !='' ">
            name = #{name}
        if>
        <if test="age > 0">
            or age > #{age}
        if>
    where>
select>
第五章 MyBatis配置文件 5.1 主配置文件

之前项目中使用的 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" >
  1. 根元素,< configguration >
    主要包含内容:
    ➢ 定义别名
    ➢ 数据源
    ➢ mapper 文件
5.2 dataSource标签

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1eV2rnyF-1648717794834)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220331164335393.png)]

Mybatis 将数据源分为三类:UNPOOLED 不使用连接池的数据源

​ POOLED 使用连接池的数据源

​ JNDI 使用 JNDI 实现的数据源

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


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UchdfcpH-1648717794836)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220331164518778.png)]

5.2.1 dataSource配置

<dataSource type="POOLED">
    
    <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>

MyBatis 在初始化时,根据的 type 属性来创建相应类型的的数据源 DataSource,即:

  1. type=”POOLED”:MyBatis 会创建 PooledDataSource 实例
  2. type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例
  3. type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用
5.3事务 5.3.1默认需要手动提交事务
  • Mybatis 框架是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的 Connection 对象的 commit(), rollback()
< transactionManager type="JDBC" />
  • Connection 对象的 setAutoCommit()方法来设置事务提交方式的。


    自动提交和手工提交、 该标签用于指定 MyBatis所使用的事务管理器。


    MyBatis 支持两种事务管理器类型:JDBC 与 MANAGED。


➢ JDBC:使用 JDBC 的事务管理机制。


即,通过 Connection 的 commit()方法提交,通过 rollback()方法 回滚。


但默认情况下,MyBatis 将自动提交功能关闭了,改为了手动提交。


即程序中需要显式的对 事务进行提交或回滚。


从日志的输出信息中可以看到。


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8NV1r14p-1648717794837)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220331165228331.png)]

➢ MANAGED:由容器来管理事务的整个生命周期(如 Spring 容器)。


5.3.2自动提交事务

设置自动提交的方式,factory 的 openSession() 分为有参数和无参数的。


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZwYBAlx6-1648717794839)(C:\Users\Dell\AppData\Roaming\Typora\typora-user-images\image-20220331165239668.png)]

有参数为 true,使用自动提交,可以修改 MyBatisUtil 的 getSqlSession()方法。


session = factory.openSession(false);

再执行 insert *** 作,无需执行 session.commit(),事务是自动提交的

5.4 使用数据库属性配置文件

数据库的属性配置文件: 把数据库连接信息放到一个单独的文件中。


和mybatis主配置文件分开。


目的是便于修改,保存,处理多个数据库的信息。


MyBatis 主配置文件需要从这个属性文件中读取这些数据。


步骤:

5.4.1在 classpath 路径下,创建 properties 文件

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


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

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


<properties resource="jdbc.properties" />
5.4.3 使用key值
<dataSource type="POOLED">
    
    <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>
5.5 mappers(映射器) 5.5.1 < mapper resource=" " />

使用相对于类路径的资源,从 classpath 路径查找文件 例如:


<mappers>
    
    <mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
    <mapper resource="com/bjpowernode/dao/OrderDao.xml" />
mappers>
5.5.2 < package name=" " />

指定包下的所有 Dao 接口

<mappers>
	
    <package name="com.bjpowernode.dao"/>
    <package name="com.bjpowernode.dao2"/>
    <package name="com.bjpowernode.dao3"/>
mappers>

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


< mapper >里面填的是路径,而< package >是包名

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/563450.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-02
下一篇 2022-04-02

发表评论

登录后才能评论

评论列表(0条)

保存