MyBatis入门


MyBatis

JDK - 静态代理

静态代理要求目标和代理对象实现同一个业务接口. 代理对象中的核心功能是由目标来完成的, 代理对象负责增强功能.

什么是静态代理

它是代理模式的一种.
它具备以下特点:

  1. 目标对象和代理对象实现同一个业务接口
  2. 目标对象必须实现接口
  3. 代理对象在程序运行前就已经存在
  4. 能够灵活的进行目标对象的切换,却无法进行功能的灵活处理(使用动态代理解决此问题)

静态代理的实现

业务功能:请明星进行节目表演.
明星刘德华:目标对象(无法直接访问)
刘德华助理:代理对象(我们可以访问,他还可以跟明星对接)
我们 :客户端对象

代码实现

业务接口 :

  public interface Service {
    //规定的唱歌的业务功能
    void sing();
  }

目标对象 :

    /**
     *   目标对象:刘德华,实现业务接口中的功能,进行唱歌表演
     */
    public class SuperStarLiu implements Service {
        @Override
        public void sing() {
            System.out.println("我是刘德华,我正在表演唱歌............");
        }
    }

代理对象 :

    public class Agent implements Service {

    //类中的成员变量设计为接口
    public Service target;  //目标对象

    //传入目标对象,方法的参数设计为接口
    public Agent(Service target){
        this.target = target;
    }

    @Override
    public void sing() {
        System.out.println("预订时间..........");
        System.out.println("预订场地..........");

        //切记切记:业务功能必须由目标对象亲自实现
//        SuperStarLiu liu = new SuperStarLiu();
//        liu.sing();
//
//        SuperStarZhou zhou = new SuperStarZhou();
//        zhou.sing();

        //面向接口编程:调用时,接口指向实现类
        target.sing();

        System.out.println("结算费用..........");
    }
}

客户端对象 :

   @Test
    public void testAgent(){
    //测试功能
    //        SuperStarLiu liu = new SuperStarLiu();
    //        liu.sing();

    //        Agent agent = new Agent();
    //        agent.sing();

            //有接口和实现类,必须使用接口指向实现类(规范)
            Service agent = new Agent();
            agent.sing();
        }
注意 : 什么是面向接口编程

类中的成员变量设计为接口, 方法的形参设计为接口, 方法的返回值设计为接口, 调用时接口指向实现类.

JDK - 动态代理

代理对象在程序运行的过程中动态在内存构建.可以灵活的进行业务功能的切换.

什么是动态代理

  1. 目标对象必须实现业务接口
  2. JDK代理对象不需要实现业务接口
  3. JDK动态代理的对象在程序运行前不存在.在程序运行时动态的在内存中构建
  4. JDK动态代理灵活的进行业务功能的切换
  5. 本类中的方法(非接口中的方法)不能被代理

动态代理用到的类和接口

1. Proxy类

它是java.lang.reflect.Proxy包下的类. 它有一个方法Proxy.newProxyInstance(…..)专门用来生成动态代理对象.

public static Object newProxyInstance(ClassLoader loader,  //类加载器
                                      Class<?>[] interfaces,//目标对象实现的所有接口
                                      InvocationHandler h) //它就类似于Agent的功能,代理的功能和目标对象的业务功能调用在这
        throws IllegalArgumentException
    {...}
2. Method类

反射用的类,用来进行目标对象的方法的反射调用.

method对象接住我们正在调用的方法sing(),show()

method==sing(),show()

method.invoke();==>手工调用目标方法 sing(); show();

3. InvocationHandler接口

它是实现代理和业务功能的.我们在调用时使用匿名内部实现.

接口能够指向所有的实现类.

如果在测试类中把Service agent = (Service)factory.getAgent(); 换成ServiceImpl agent = (ServiceImpl)factory.getAgent(); 是不行的.

  • 因为此时的 ServiceImpl 对象不是 之前的 ServiceImpl 对象, 而是被代理类增强后, 有增强功能的 ServiceImpl 对象, ServiceImpl类无法接住此对象.
  • 使用接口可以指向新的实现.

一个简易MyBatis框架

常用的框架SSM

Spring : 它是整合其它框架的框架. 它的核心是IOC和AOP.

SpringMVC : 它是Spring家族的一员, 专门用来优化控制器的.提供了极简单数据提交, 数据携带, 页面跳转等功能.

MyBatis : 是持久化层的一个框架. 用来进行数据库访问的优化. 专注于sql语句. 极大简化了JDBC的访问.

添加框架的步骤 :

  1. 新建库建表

  2. 新建maven项目

  3. 修改目录, 添加缺失的目录

  4. 修改pom.xml文件, 添加MyBatis的依赖, 添加MySQL的依赖

  5. 修改pom.xml文件, 添加资源文件的指定

  6. 在idea中添加数据库的可视化

  7. 添加jdbc.properties配置文件(数据库的配置)

    jdbc.driverClassName=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    jdbc.username=root
    jdbc.password=123456
    
  8. 添加SqlMapConfig.xml文件(MyBatis的核心配置文件)

    注意文件头

    <?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>
        <!--读取jdbc属性文件-->
    
        <!--设置日志输出-->
    
        <!--注册实体类别名-->
    
        <!--配置环境变量-->
    
        <!--注册mapper.xml-->
    </configuration>
    

    具体实现

    <?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>
        <!--读取属性文件(jdbc.properties)
            属性:
                resource:从resource目录下找指定名称的文件加载(相对路径)
                url:使用绝对路径加载属性文件
        -->
        <properties resource="jdbc.properties"></properties>
    
        <!--配置数据库的环境变量(数据库连接配置)
            default:使用下面的environment标签的id属性进行指定配置
        -->
        <environments default="development">
            <!--在公司开发时用的配置
                id:就是提供给environment的default属性使用
            -->
            <environment id="development">
                <!--配置事务管理器 - transactionManager
                    type:指定事务管理的方式(追源码可知道有两种选项:jdbc/managed
                        JDBC:事务的控制交给程序员来出来
                        MANAGED:由容器(spring)来管理事务
                -->
                <transactionManager type="JDBC"></transactionManager>
                <!--配置数据源 - dataSource
                    type:指定不同的配置方式(追源码可知有三种属性:jndi/pooled/unpooled
                        JNDI:java命名目录接口在服务器(tomcat)端进行数据库连接池的管理
                        POOLED:使用数据库连接池
                        UNPOOLED:不使用数据库连接池
                -->
                <dataSource type="POOLED">
                    <!--配置数据库连接池的基本参数
                        private String driver;
                        private String url;
                        private String username;
                        private String password;
                    -->
                    <property name="driver" value="${jdbc.driverClassName}"></property>
                    <property name="url" value="${jdbc.url}"></property>
                    <property name="username" value="${jdbc.username}"></property>
                    <property name="password" value="${jdbc.password}"></property>
                </dataSource>
            </environment>
            <!--在家开发时用的配置-->
    <!--
            <environment id="home">
                <transactionManager type=""></transactionManager>
                <dataSource type=""></dataSource>
            </environment>
    -->
            <!--上线时用的配置-->
    <!--
            <environment id="online">
                <transactionManager type=""></transactionManager>
                <dataSource type=""></dataSource>
            </environment>
    -->
        </environments>
        <!--注册mapper.xml文件
            resource:从resource目录下找指定名称的文件进行注册
            url:使用绝对路径注册
            class:动态代理方式下的注册
        -->
        <mappers>
            <mapper resource="StudentMapper.xml"></mapper>
        </mappers>
    
    </configuration>
    
  9. 创建实体类Student, 用来封装数据

    当前使用的是实体类的成员变量和数据库中的列名相同, 完成映射

    在后续也可以使用别名进行成员变量和数据库列名的映射 => 详见 resultMap的简单用法

    package com.bjpowernode.pojo;
    
    public class Student {
        private Integer id;
        private String name;
        private String email;
        private Integer age;
    
        public Student() {
        }
        //做添加的时候, 因为id是自增的, 所以不用给值
        public Student(String name, String email, Integer age) {
            this.name = name;
            this.email = email;
            this.age = age;
        }
    
        public Student(Integer id, String name, String email, Integer age) {
            this.id = id;
            this.name = name;
            this.email = email;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", email='" + email + '\'' +
                    ", age=" + 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;
        }
    }
    
  10. 添加完成学生表的增删改查的功能的StudentMapper.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:是整个文件的大标签,用来开始和结束xml文件
        属性:
            namespace:指定命名空间(相当于包名),用来区分不同mapper.xml文件中相同的id属性
            
    -->
    <mapper namespace="csd">
        <!--查询语句,用到查询时,直接调用id就行-->
            <!--完成查询全部学生的功能
                resultType:指定查询返回的结果集的类型,如果是集合,则必须是泛型的类型
                parameterType:如果有参数,则通过它来指定参数的类型
            -->
        <select id="getAll" resultType="com.bjpowernode.beans.Student">
            <!--用来写sql语句-->
            select id,name,email,age from student;
        </select>
    </mapper>
    
  11. 创建测试类, 进行功能测试

    
    public class MyTest {
        @Test
        public void testA() throws IOException {
    
            //使用文件流读取核心配置文件SqlMapConfig.xml
            InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
            //创建SqlSessionFactory工厂
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
            //取出sqlSession对象
            SqlSession sqlSession = factory.openSession();
            //完成查询操作
            List list = sqlSession.selectList("csd.getAll");
            list.forEach(student -> System.out.println(student));
            //关闭sqlSession
            sqlSession.close();
        }
    }
    

增删改查的功能

查询

StudentMapper.xml中

    <!--按主键ID查询-->
    <!--  原先的方法是 :public Student getById(Integer id){}
           mybatis中映射关系查表得 int => Integer
    -->
    <select id="getById" parameterType="int" resultType="com.bjpowernode.beans.Student">
        <!--#{}表示占位符,也就是在jdbc中的 ?-->
        select id,name,email,age from student where id=#{id};
    </select>

    <!--模糊查询-->
    <!--原先的方法是 List<Student> getByName(String name){}
        mybatis中映射关系查表得 string => String
    -->
    <select id="getByName" parameterType="string" resultType="com.bjpowernode.beans.Student">
        <!--${}表示字符串拼接,有两个尖角 '' 只能使用${} -->
        select id,name,email,age from student where name like '%${name}%';
    </select>

测试类

    @Test
    public void testGetById() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //取出sqlSession对象
        SqlSession sqlSession = factory.openSession();
        //完成查询操作  (按主键ID查询)
        Student stu = sqlSession.selectOne("csd.getById", 2);
        System.out.println(stu);
        //关闭sqlSession
        sqlSession.close();
    }

    @Test
    public void testGetByName() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //取出sqlSession对象
        SqlSession sqlSession = factory.openSession();
        //完成查询操作  (模糊查询)
        List<Student> list = sqlSession.selectList("csd.getByName", "张");
        list.forEach(student -> {
            System.out.println(student);
        });
        //关闭sqlSession
        sqlSession.close();
    }

增加

StudentMapper.xml中

    <!--增加学生-->
    <!--原先的方法是 int insert(Student stu){}
        增删改中, mybatis自动返回, 没有resultType
    -->
    <select id="insert" parameterType="com.bjpowernode.beans.Student">
        insert into student(name,email,age) values(#{name},#{email},#{age});
    </select>

测试类

    @Test
    public void testInsert() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //取出sqlSession对象
        SqlSession sqlSession = factory.openSession();
        //增加学生  使用到Student的除主键外的全参构造器
        int num = sqlSession.insert("csd.insert", new Student("刘六","123@qq.com",22));
        //需要手动提交
        sqlSession.commit();
        //关闭sqlSession
        sqlSession.close();
    }

删除

StudentMapper.xml中

    <!--按主键删除学生-->
    <!--原先的方法是 int delete(Integer id){}-->
    <select id="delete" parameterType="int">
        delete from student where id = #{id};
    </select>

测试类

    @Test
    public void testDelete() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //取出sqlSession对象
        SqlSession sqlSession = factory.openSession();
        //删除学生
        int num = sqlSession.delete("csd.delete", 5);
        //需要手动提交
        sqlSession.commit();
        //关闭sqlSession
        sqlSession.close();
    }

更新

StudentMapper.xml中

    <!--按主键更新学生数据-->
    <!--原先的方法是 int update(Student stu)-->
    <select id="update" parameterType="com.bjpowernode.beans.Student">
        update student set name=#{name},email=#{email},age=#{age} where id=#{id};
    </select>

测试类

    @Test
    public void testUpdate() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //取出sqlSession对象
        SqlSession sqlSession = factory.openSession();
        //更新学生数据    使用到了Student类的全参构造器
        int num = sqlSession.update("csd.update", new Student(6,"刘拉拉","456@qq.com",18));
        //需要手动提交
        sqlSession.commit();
        //关闭sqlSession
        sqlSession.close();
    }

MyBatis对象分析

  1. Resources类

    用来解析SqlMapConfig.xml文件, 创建出相应的对象

  2. SqlSessionFactory接口

  3. SqlSession接口

代码优化

实体类别名注册

在写sql语句时, 有返回值类型需要重复写, 我们这里可以给它在SqlMapConfig.xml文件中起别名, 注意使用标签的顺序.

http://mybatis.org/dtd/mybatis-3-config.dtd我们可以看到标签顺序是 :

    <!--注册实体类别名,用于重复使用-->
    <typeAliases>
        <!--单个实体类别名注册-->
        <typeAlias type="com.bjpowernode.beans.Student" alias="student"></typeAlias>
        <!--批量注册别名
            别名是类名的驼峰命名法  Student => student      StudentOne  =>  studentOne
        -->
        <package name="com.bjpowernode.beans"></package>
    </typeAliases>

测试类的优化

在写测试类中, 我们发现有重复代码需要不断的实现. 那么我们可以使用@Before与@After注解

    public SqlSession sqlSession;
    @Before   //在所有的Test方法前先执行以下代码
    public void openSqlSession() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //取出sqlSession对象
        sqlSession = factory.openSession();
    }
    @After  //在所有Test方法后执行以下代码
    public void closeSqlSession(){
        //关闭sqlSession
        sqlSession.close();
    }

设置日志输出

在SqlMapConfig.xml文件设置

    <!--设置日志输出底层执行的代码-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

优化mapper.xml注册

在SqlMapConfig.xml文件设置

    <!--注册mapper.xml-->
    <mappers>
        <!--<mapper class="com.bjpowernode.mapper.UserMapper"></mapper>-->
        <!--批量注册-->
        <package name="com.bjpowernode.mapper"/>
    </mappers>

如何访问数据访问层

在三层架构中, 业务逻辑层要通过接口访问数据访问层的功能, 动态代理可以实现

动态代理的实现规范

使用动态代理时, Mapper.xml ( sql语句不能使用select来进行增删改, 必须根据当前sql语句的使用场景使用, 而普通方法可以使用select完成增删改查 )

  1. UsersMapper.xml文件与UsersMapper.java的接口必须同一个目录下.
  2. UsersMapper.xml文件与UsersMapper.java的接口的文件名必须一致,后缀不管.
  3. UserMapper.xml文件中标签的id值与与UserMapper.java的接口中方法的名称完全一致.
  4. UserMapper.xml文件中标签的parameterType属性值与与UserMapper.java的接口中方法的参数类型完全一致.
  5. UserMapper.xml文件中标签的resultType值与与UserMapper.java的接口中方法的返回值类型完全一致.
  6. UserMapper.xml文件中namespace属性必须是接口的完全限定名称com.bjpowernode.mapper.UsersMapper
  7. 在SqlMapConfig.xml文件中注册mapper文件时,使用class=接口的完全限定名称com.bjpowernode.mapper.UsersMapper.

实现步骤

  1. 建表Users

  2. 新建maven工程

  3. 修改目录

  4. 修改pom.xml文件, 添加依赖

  5. 添加jdbc.properties文件到resources目录下

  6. 添加SqlMapConfig.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>
        <!--读取jdbc属性文件-->
        <properties resource="jdbc.properties"></properties>
        <!--设置日志输出-->
        <settings>
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
        <!--注册实体类别名-->
        <typeAliases>
            <package name="com.bjpowernode.pojo"></package>
        </typeAliases>
        <!--配置环境变量-->
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"></transactionManager>
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driverClassName}"></property>
                    <property name="url" value="${jdbc.url}"></property>
                    <property name="username" value="${jdbc.username}"></property>
                    <property name="password" value="${jdbc.password}"></property>
                </dataSource>
            </environment>
        </environments>
        <!--注册mapper.xml-->
        <mappers>
            <mapper class="com.bjpowernode.mapper.UserMapper"></mapper>
        </mappers>
    </configuration>
    
  7. 添加实体类

    package com.bjpowernode.pojo;
    
    import java.util.Date;
    
    public class Users {
        private Integer id;
        private String userName;
        private Date birthday;
        private String sex;
        private String address;
    
        public Users() {
        }
    
        @Override
        public String toString() {
            return "Users{" +
                    "id=" + id +
                    ", userName='" + userName + '\'' +
                    ", birthday=" + birthday +
                    ", sex='" + sex + '\'' +
                    ", address='" + address + '\'' +
                    '}';
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public Users(String userName, Date birthday, String sex, String address) {
            this.userName = userName;
            this.birthday = birthday;
            this.sex = sex;
            this.address = address;
        }
    
        public Users(Integer id, String userName, Date birthday, String sex, String address) {
            this.id = id;
            this.userName = userName;
            this.birthday = birthday;
            this.sex = sex;
            this.address = address;
        }
    }
    
  8. 添加mapper文件夹, 新建UsersMapper接口

    package com.bjpowernode.mapper;
    
    import com.bjpowernode.pojo.Users;
    
    import java.util.List;
    
    /**
     * 数据访问层的接口,规定的数据库中可以进行的各种操作
     */
    public interface UserMapper {
        //查询所有用户
        List<Users> getAll();
    }
    
  9. 在mapper文件夹下, 新建UsersMapper.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="com.bjpowernode.mapper.UserMapper">
        <!--
            //查询所有用户
            List<Users> getAll();
        -->
        <select id="getAll" resultType="users">
            select id,username,birthday,sex,address from users;
        </select>
    </mapper>
    
  10. 添加测试类

        @Test
        public void testGetAll01(){
            //取出动态代理的对象,完成接口中方法的调用,实则是调用xml文件中标签的功能
            UserMapper userMapper = session.getMapper(UserMapper.class);
            //xml相当于接口的实现类,getAll被动态代理出来
            List<Users> users = userMapper.getAll();
            users.forEach(users1 -> {
                System.out.println(users1);
            });
        }
    //在@Test前面添加注解@Before和@After
    

接口类

使用接口类, 让xml实现接口, 从而达到动态代理来访问数据访问层

package com.bjpowernode.mapper;

import com.bjpowernode.pojo.Users;

import java.util.List;

/**
 * 数据访问层的接口,规定的数据库中可以进行的各种操作
 */
public interface UserMapper {
    //查询所有用户
    List<Users> getAll();
    //根据用户主键查用户
    Users getById(Integer id);
    //根据用户名模糊查询
    List<Users> getByName(String name);
    //用户的更新
    int update(Users users);
    //增加用户
    int insert(Users users);
    //根据主键删除用户
    int delete(Integer id);
}

查询

    <!--根据主键查找用户-->
    <select id="getById" resultType="users" parameterType="int">
        select id,username,birthday,sex,address from users where id = #{id};
    </select>

    <!--根据用户名模糊查询-->
    <select id="getByName" resultType="users" parameterType="string">
        select id,username,birthday,sex,address from users where username like '%${username}%';
    </select>

测试类

    @Test
    public void testGetById01(){
        Users users = userMapper.getById(7);
        System.out.println(users);
    }

    @Test
    public void testGetByName(){
        List<Users> users = userMapper.getByName("张");
        users.forEach(users1 -> {
            System.out.println(users1);
        });
    }
//注意使用注解进行重复代码封装

增加

    <!--增加用户-->
    <insert id="insert" parameterType="users">
        insert into users(username, birthday, sex, address) values (#{userName},#{birthday},#{sex},#{address});
    </insert>

测试类

    //时间刷子
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");    //用来完成生日的格式转换
    

    @Test
    public void testInsert() throws ParseException {
        int num = userMapper.insert(new Users("牛奶", simpleDateFormat.parse("1999-1-1"), "1", "上海"));
        System.out.println(num);
        session.commit();
    }

删除

    <!--删除用户-->
    <delete id="delete" parameterType="int">
        delete from users where id=#{id};
    </delete>

测试类

    @Test
    public void testDelete(){
        int num = userMapper.delete(2);
        System.out.println(num);
        session.commit();
    }

更新

    <!--用户的更新-->
    <update id="update" parameterType="users">
        update users set username=#{userName},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id};
    </update>

测试类

    @Test
    public void testUpdate() throws ParseException {
        Users u = new Users(2, "豆奶", simpleDateFormat.parse("2000-3-1"),"2","北京" );
        int num = userMapper.update(u);
        System.out.println(num);
        session.commit();
    }

#{} 与 ${}

#{} 占位符

传参大部分使用#{}传参,它的底层使用的是PreparedStatement对象,是安全的数据库访问 ,防止sql注入.

#{ } 里面如何写? 看paramenterType参数的类型

  1. 如果parameterType的类型是简单类型(8种基本(封装)+String),则#{}里随便写.

     <select id="getById" parameterType="int" resultType="users">  ===>入参类型是简单类型
            select id,username,birthday,sex,address
            from users
            where id=#{zar}  ===>随便写
     </select>  
    
  2. parameterType的类型是实体类的类型,则#{}里只能是类中成员变量的名称,而且区分大小写.

    <insert id="insert" parameterType="users" >  ===>入参是实体类
            insert into users (username, birthday, sex, address) values(#{userName},#{birthday},#{sex},#{address})  ==>成员变量名称
    </insert>
    

${} 字符串拼接或字符串替换

  1. 字符串拼接,一般用于模糊查询中.建议少用,因为有sql注入的风险.

    也分两种情况, 同样看parameterType的类型

  2. 字符串替换

    需求 : 模糊地址和用户查询

    select * from users where username like '%小%';
    select * from users where address like '%市%';
    
    -- 两个查询语句只有两处不同,可以优化
    

优化模糊查询

<!--
    //优化后的模糊查询
    List<Users> getByNameGood(String name);
-->
<select id="getByNameGood" parameterType="string" resultType="users">
        select id,username,birthday,sex,address
        from users
        where username like concat('%',#{name},'%')//把${}换成#{}
</select>

优化多个参数的模糊查询

接口类

//模糊地址和用户查询的方法
List<Users> getByNameOrAddress(
            @Param("columnName")  ===>为了在sql语句中使用的名称
            String columnName,
            @Param("columnValue")   ===>为了在sql语句中使用的名称
            String columnValue);

UsersMapper.xml文件

<!--
    //模糊地址和用户查询
    //如果参数超过一个,则parameterType不写
    List<Users> getByNameOrAddress(
    @Param("columnName")    ===>为了在sql语句中使用的名称
    String columnName,
    @Param("columnValue")   ===>为了在sql语句中使用的名称
    String columnValue);

                                        //columnName列名
-->
<select id="getByNameOrAddress" resultType="users">
        select id,username,birthday,sex,address
        from users
        where ${columnName} like concat('%',#{columnValue},'%')  ==>  使用${}来替换列名
</select> ==> 使用的是@Param注解里的名称

测试类

@Test
public void testGetByNameOrAddress(){
    List<Users> list = uMapper.getByNameOrAddress("username","小");//按用户名(列名)来模糊查询
    list.forEach(users -> System.out.print(users));
}
parameterType总结 :
  • 如果参数超过一个,则parameterType不写
  • 如果不是实体类和简单类型, 则parameterType不写
resultType总结 :
  1. 增删改中, mybatis自动返回, 没有resultType

返回主键标签

在完成插入操作后, 将生成的主键信息通过实体类对象返回, 在进行后续关联插入操作时, 不用再次访问数据库

流程分析

实现步骤

在UsersMapper.xml文件中

    <!--增加用户,返回主键-->
    <insert id="insert" parameterType="users">
    <selectKey keyProperty="id" resultType="int" order="AFTER">
        select last_insert_id();
    </selectKey>
        insert into users(username, birthday, sex, address) values (#{userName},#{birthday},#{sex},#{address});
    </insert>
<!--
    <selectKey>标签的参数详解:
    keyProperty: users对象的哪个属性来接返回的主键值(id)
    resultType:返回的主键的类型
    order:在插入语句执行前,还是执行后返回主键的值
-->

UUID

这是一个全球唯一随机字符串,由36个字母数字中划线组.

java中

    @Test
    public void testUUID(){
        UUID uuid = UUID.randomUUID();
        System.out.println(uuid);
    }

MySQL中

select uuid();

动态sql

可以定义代码片段,可以进行逻辑判断,可以进行循环处理(批量处理),使条件判断更为简单.

标签sql与include

  1. : 用来定义代码片段,可以将所有的列名,或复杂的条件定义为代码片段,供使用时调用.
  2. : 用来引用定义的代码片段.

在UsersMapper.xml文件中

    <!--定义代码片段-->
    <sql id="allColumns">
        id,username,birthday,sex,address
    </sql>

    <!--
        //查询所有用户
        List<Users> getAll();
    -->
    <select id="getAll" resultType="users">
        select <include refid="allColumns"></include> from users;
    </select>

标签if与where

  1. : 进行条件判断
  2. : 进行多条件判断, 在查询, 删除, 更新时使用

实现步骤

接口类

    //按指定的条件进行多条件查询
    List<Users> getByCondition(Users users);

在UsersMapper.xml文件中

    <!--
    //按指定的条件进行多条件查询
    List<Users> getByCondition(Users users);
    根据实体类中的成员变量是否有值来决定是否添加条件
    -->
    <select id="getByCondition" resultType="users" parameterType="users">
        select <include refid="allColumns"></include> from users
        <where>
            <if test="userName != null and userName != ''">
                and username like concat('%',#{userName},'%')
            </if>
            <if test="birthday != null">
                and birthday = #{birthday}
            </if>
            <if test="sex != null and sex != ''">
                and sex = #{sex}
            </if>
            <if test="address != null and address != ''">
                and address like concat('%',#{address},'%')
            </if>
        </where>
    </select>

测试类

    @Test
    public void getByCondition() throws ParseException {
        Users users = new Users();
        //给什么赋值就是查什么
        users.setSex("1");
        users.setBirthday(simpleDateFormat.parse("1999-01-01"));
        List<Users> list = userMapper.getByCondition(users);
        list.forEach(users1 -> System.out.println(users1));
    }

标签set

  1. : 有选择的进行更新处理, 至少更新一列

当我们在进行更新操作的时候, 如果按照以前的方法进行更新, 想要只更新一个名字时, 会发现修改了名字后, 其他没有赋值的列也被更新了(为null)

实现步骤

接口类

    //有选择性的更新
    int updateBySet(Users users);

在UsersMapper.xml文件中

    <!--
    //有选择性的更新
    int updateBySet(Users users);
    -->
    <update id="updateBySet" parameterType="users">
        update users
        <set>
            <if test="userName != null and userName != ''">
                username = #{userName},
            </if>
            <if test="birthday != null">
                birthday = #{birthday},
            </if>
            <if test="sex != null and sex != ''">
                sex = #{sex},
            </if>
            <if test="address != null and address !=''">
                address = #{address},
            </if>
        </set>
        where id = #{id};  ==>注意不用漏掉
    </update>

测试类

    @Test
    public void updateBySet(){
        Users users = new Users();
        users.setId(27);
        users.setAddress("泉州");
        int num = userMapper.updateBySet(users);
        System.out.println(num);
        session.commit();
    }

标签foreach

  1. : 用来进行循环遍历,完成循环条件查询,批量删除(经常用),批量增加(偶尔用),批量更新(很少用).

实现步骤

接口类

    //查询多个指定id用户的信息
    List<Users> getByIds(Integer arr[]);

在UsersMapper.xml文件中

    <!--
    //查询多个指定id用户的信息
    List<Users> getByIds(Integer arr[]);
    当前使用的参数是数组, 所以foreach当中的collecting是arrays
    如果是list集合就是list
    是map集合就是map
    -->
    <select id="getByIds" resultType="users">
        select <include refid="allColumns"></include>
        from users
        where id in
        <foreach collection="array" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </select>

测试类

    @Test
    public void getByIds(){
        Integer[] arr = {3,4,5};
        List<Users> list = userMapper.getByIds(arr);
        list.forEach(users -> System.out.println(users));
    }

foreach标签参数详解

  • collection:用来指定入参的类型,如果是List集合,则为list,如果是Map集合,则为map,如果是数组,则为array.
  • item:每次循环遍历出来的值或对象
  • separator:多个值或对象或语句之间的分隔符
  • open:整个循环外面的前括号
  • close:整个循环外面的后括号

批量删除

实现步骤

接口类

    //批量删除
    int deleteAll(Integer arr[]);

在UsersMapper.xml文件中

    <!--
    //批量删除
    int deleteAll(Integer arr[]);
    -->
    <delete id="deleteAll">
        delete from users where id in
        <foreach collection="array" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>

测试类

    @Test
    public void deleteAll(){
        Integer[] arr = {27,28,29};
        int num = userMapper.deleteAll(arr);
        System.out.println(num);
        session.commit();
    }

批量增加

实现步骤

接口类

    //批量增加
    int insertAll(List list);

在UsersMapper.xml文件中

    <!--
    //批量增加
    int insertAll(List list);
    注意要使用u.userName....    因为是封装到对象u中去
    -->
    <insert id="insertAll">
        insert into users(username, birthday, sex, address) values
        <foreach collection="list" separator="," item="u">
            (#{u.userName},#{u.birthday},#{u.sex},#{u.address})
        </foreach>
    </insert>

测试类

    @Test
    public void testInsertAll() throws ParseException {
        Users users = new Users("a", simpleDateFormat.parse("1999-01-01"), "2", "广东");
        Users users1 = new Users("b", simpleDateFormat.parse("1999-01-01"), "2", "广东1");
        Users users2 = new Users("c", simpleDateFormat.parse("1999-01-01"), "2", "广东2");
        Users users3 = new Users("d", simpleDateFormat.parse("1999-01-01"), "2", "广东3");
        List<Users> list = new ArrayList();
        list.add(users);
        list.add(users1);
        list.add(users2);
        list.add(users3);
        int num = userMapper.insertAll(list);
        System.out.println(num);
        session.commit();
    }

指定参数位置(使用下标)

如果入参是多个,可以通过指定参数位置进行传参. 是实体包含不住的条件.实体类只能封装住成员变量的条件.如果某个成员变量要有区间范围内的判断,或者有两个值进行处理,则实体类包不住.

例如:查询指定日期范围内的用户信息.

如何指定

接口类

    //查询指定日期范围内的用户信息
    List<Users> getByDate(Date begin, Date end);

在UsersMapper.xml文件中

    <!--
    //查询指定日期范围内的用户信息
    List<Users> getByDate(Date begin, Date end);
    有默认的下标, 从0开始, 也就是从arg0开始
    -->
    <select id="getByDate" resultType="users">
        select <include refid="allColumns"></include>
        from users
        where birthday between #{arg0} and #{arg1};
    </select>

测试类

    @Test
    public void testGetByDate() throws ParseException {
        Date begin = simpleDateFormat.parse("1999-01-01");
        Date end = simpleDateFormat.parse("1999-12-31");
        List<Users> list = userMapper.getByDate(begin, end);
        list.forEach(users -> System.out.println(users));
    }

指定参数位置(@Param指定参数位置)

  • 详见 : 优化多个参数的模糊查询示例

指定参数位置(入参是map)

如果入参超过一个以上, 使用map封装查询条件, 更有语义, 查询条件更明确.

实现步骤

接口类

    //入参是map, 查询指定日期范围内的用户信息
    List<Users> getByMap(Map map);

在UsersMapper.xml文件中

    <!--
    //入参是map, 查询指定日期范围内的用户信息
    List<Users> getByMap(Map map);
    Map里面的成员变量是啥
    #{birthdaybegin} 与 #{birthdayend} : 就是map中的key
    -->
    <select id="getByMap" resultType="users">
        select <include refid="allColumns"></include>
        from users
        where birthday between #{birthdaybegin} and #{birthdayend};
    </select>

测试类

    @Test
    public void testGetByMap() throws ParseException {
        Date begin = simpleDateFormat.parse("1999-01-01");
        Date end = simpleDateFormat.parse("1999-12-31");
        Map map = new HashMap<>();
        map.put("birthdaybegin", begin);
        map.put("birthdayend", end);
        List<Users> list = userMapper.getByMap(map);
        list.forEach(users -> System.out.println(users));
    }

返回一行Map

如果返回的数据实体类无法包含, 可以使用map返回多张表中的若干数据. 返回后这些数据之间没有任何关系. 就是Object类型. 返回的map的key就是列名或别名.

接口类

    //返回一行map   返回姓名和地址封装到map中
    Map getReturnMapOne(Integer id);

在UsersMapper.xml文件中

    <!--
    //返回一行map
    Map getReturnMapOne(Integer id);
    -->
    <select id="getReturnMapOne" resultType="map" parameterType="int">
        select username,address from users
        where id = #{id};
    </select>

测试类

    @Test
    public void testReturnMapOne(){
        Map map = userMapper.getReturnMapOne(1);
        System.out.println(map.get("username"));
    }

返回多行Map

接口类

    //返回多行map
    List<Map> getMulMap();

在UsersMapper.xml文件中

    <!--
    //返回多行map
    List<Map> getMulMap();
    -->
    <select id="getMulMap" resultType="map">
        select username,address from users
    </select>

测试类

    @Test
    public void testGetMulMap(){
        List<Map> list = userMapper.getMulMap();
        list.forEach(map -> System.out.println(map));
    }

resultMap的简单用法

在之前我们提到实体类中的成员变量需要和数据库中的列名相同, 以此来完成映射

在这里我们要介绍的是还有两种方法可以完成映射

  1. 使用别名进行成员变量和数据库列名的映射

    • 我们可以在写sql语句时, 使用别名(给数据库中的列名起别名)来完成数据库列名与实体类成员变量的名称一致

          <select id="getAll" resultType="bookmap">
              select bookid id,bookname name from book;
          </select>
      
  2. 使用resultMap

    • 在之前我们的返回类型都是使用resultType , 但是当出现实体类成员变量与数据库列名不一致时, 我们就不能单纯的使用它了, 需要在sql语句起别名, 那么有没有其他的方法呢 ?

    • 我们可以使用resultMap 来自定义

    • 举例 : 查询所有图书, 图书的实体类与数据库列名不同

      //实体类
      private Integer id; 
      private String name;
      //数据库列名
      //  bookid 与 bookname
      
    • 实现步骤

      在UsersMapper.xml文件中

      •     <!--使用resultMap完成手工映射-->
            <resultMap id="bookmap" type="book">
                <!--主键绑定 property指的是实体类的成员变量, column指的是数据库中的列名 -->
                <id property="id" column="bookid"></id>
                <!--非主键绑定-->
                <result property="name" column="bookname"></result>
            </resultMap>
            <select id="getAll" resultMap="bookmap">
                select bookid,bookname from book;
            </select>
        

关联关系

一对多关联关系

客户和订单就是典型的一对多关联关系.
一个客户名下可以有多个订单.
客户表是一方,订单表是多方.客户一中持有订单的集合.
使用一对多的关联关系,可以满足查询客户的同时查询该客户名下的所有订单.

实现步骤

1.创建实体类

客户实体类

public class Customer {
    private Integer id;
    private String name;
    private Integer age;
    //客户名下的所有订单信息
    private List<Orders> ordersList;

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", ordersList=" + ordersList +
                '}';
    }

    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 Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public List<Orders> getOrdersList() {
        return ordersList;
    }

    public void setOrdersList(List<Orders> ordersList) {
        this.ordersList = ordersList;
    }

    public Customer(Integer id, String name, Integer age, List<Orders> ordersList) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.ordersList = ordersList;
    }

    public Customer() {
    }
}

订单实体类

package com.bjpowernode.pojo;

public class Orders {
    private Integer id;
    private String orderNumber;
    private Double orderPrice;

    @Override
    public String toString() {
        return "Orders{" +
                "id=" + id +
                ", orderNumber='" + orderNumber + '\'' +
                ", orderPrice=" + orderPrice +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getOrderNumber() {
        return orderNumber;
    }

    public void setOrderNumber(String orderNumber) {
        this.orderNumber = orderNumber;
    }

    public Double getOrderPrice() {
        return orderPrice;
    }

    public void setOrderPrice(Double orderPrice) {
        this.orderPrice = orderPrice;
    }

    public Orders(Integer id, String orderNumber, Double orderPrice) {
        this.id = id;
        this.orderNumber = orderNumber;
        this.orderPrice = orderPrice;
    }

    public Orders() {
    }
}
2.创建Mapper文件

我们现在需要由客户来查信息, 所以创建的是CustomerMapper

CustomerMapper接口

/**
 * 数据访问层的接口,规定的数据库中可以进行的各种操作
 */
public interface CustomerMapper {
    //根据客户ID查询客户所有信息,并且返回客户的所有订单信息
    Customer getById(Integer id);
}

CustomerMapper.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="com.bjpowernode.mapper.CustomerMapper">
    <!--
    //根据客户ID查询客户所有信息,并且返回客户的所有订单信息
    Customer getById(Integer id);
    select 字段列表 from 表1 left [outer] join 表2 on 条件...;
    ofType指泛型的类型 ==> //客户名下的所有订单信息,一方持有多方的集合
                          private List<Orders> ordersList;
    -->
    <resultMap id="customermap" type="customer">
        <!--主键绑定,注意数据库中id已经起了别名-->
        <id property="id" column="cid"></id>
        <!--非主键绑定-->
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <!--ordersList绑定, 返回的订单信息是集合-->
        <collection property="ordersList" ofType="orders">
            <!--主键绑定,注意数据库中id已经起了别名-->
            <id property="id" column="oid"></id>
            <!--非主键绑定-->
            <result property="orderNumber" column="orderNumber"></result>
            <result property="orderPrice" column="orderPrice"></result>
        </collection>
    </resultMap>
    <select id="getById" resultMap="customermap" parameterType="int">
        select c.id cid,c.name,c.age,o.id oid,o.orderNumber,o.orderPrice,o.customer_id
        from customer c left outer join orders o on c.id = o.customer_id
        where c.id = #{id};
    </select>
</mapper>
3.测试

测试类

    @Test
    public void testGetByIdCustomer(){
        Customer customer = customerMapper.getById(3);
        System.out.println(customer);
    }

多对一关联关系

订单和客户就是多对一关联.
站在订单的方向查询订单的同时将客户信息查出.
订单是多方,会持有一方的对象.客户是一方.

实现步骤

1.创建实体类

客户实体类

public class Customer {
    private Integer id;
    private String name;
    private Integer age;
    //客户名下的所有订单信息,一方持有多方的集合
    private List<Orders> ordersList;

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", ordersList=" + ordersList +
                '}';
    }

    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 Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public List<Orders> getOrdersList() {
        return ordersList;
    }

    public void setOrdersList(List<Orders> ordersList) {
        this.ordersList = ordersList;
    }

    public Customer(Integer id, String name, Integer age, List<Orders> ordersList) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.ordersList = ordersList;
    }

    public Customer() {
    }
}

订单实体类

public class Orders {
    private Integer id;
    private String orderNumber;
    private Double orderPrice;

    //关联下此订单的客户信息, 多方持有一方的对象
    private Customer customer;

    @Override
    public String toString() {
        return "Orders{" +
                "id=" + id +
                ", orderNumber='" + orderNumber + '\'' +
                ", orderPrice=" + orderPrice +
                ", customer=" + customer +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getOrderNumber() {
        return orderNumber;
    }

    public void setOrderNumber(String orderNumber) {
        this.orderNumber = orderNumber;
    }

    public Double getOrderPrice() {
        return orderPrice;
    }

    public void setOrderPrice(Double orderPrice) {
        this.orderPrice = orderPrice;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Orders(Integer id, String orderNumber, Double orderPrice, Customer customer) {
        this.id = id;
        this.orderNumber = orderNumber;
        this.orderPrice = orderPrice;
        this.customer = customer;
    }

    public Orders() {
    }
}
2.创建Mapper文件

我们现在需要由订单来查信息, 所以创建的是OredrsMapper

OredrsMapper接口

/**
 * 数据访问层的接口,规定的数据库中可以进行的各种操作
 */
public interface OrdersMapper {
    //根据订单ID查询订单所以信息, 并返回该订单所属客户的信息
    Orders getById(Integer id);
}

OredrsMapper.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="com.bjpowernode.mapper.OrdersMapper">
    <!--
    //根据订单ID查询订单所以信息, 并返回该订单所属客户的信息
    Orders getById(Integer id);
    javaType指的是类型 ==> //关联下此订单的客户信息, 多方持有一方的对象
                          private Customer customer;
    -->
    <resultMap id="ordersmap" type="orders">
        <!--主键绑定,注意数据库中id已经起了别名-->
        <id property="id" column="oid"></id>
        <!--非主键绑定-->
        <result property="orderNumber" column="orderNumber"></result>
        <result property="orderPrice" column="orderPrice"></result>
        <!--customer绑定,返回的是客户对象-->
        <association property="customer" javaType="customer">
            <!--主键绑定,注意数据库中id已经起了别名-->
            <id property="id" column="cid"></id>
            <!--非主键绑定-->
            <result property="name" column="name"></result>
            <result property="age" column="age"></result>
        </association>
    </resultMap>
    <select id="getById" parameterType="int" resultMap="ordersmap">
        select o.id oid,o.orderNumber,o.orderPrice,o.customer_id,c.id cid,c.name,c.age
        from orders o join customer c on c.id = o.customer_id
        where o.id = #{id};
    </select>
</mapper>
3.测试

测试类

    @Test
    public void testGetByIdOrders(){
        Orders orders = ordersMapper.getById(11);
        System.out.println(orders);
    }

一对一与多对多关联关系

无论是什么关联关系,如果某方持有另一方的集合,则使用标签完成映射,如果某方持有另一方的对象,则使用标签完成映射。

多对多关联

需要使用中间表来进行过渡

多对多关联中,需要通过中间表化解关联关系。中间表描述两张主键表的关联。中间表没有对应的实体类。Mapper.xml文件中也没有中间表的对应标签描述,只是在查询语句中使用中间表来进行关联。

多对多关联

事务

多个操作同时完成,或同时失败称为事务处理.
事务有四个特性:一致性,持久性,原子性,隔离性.

在MyBatis框架中设置事务 : mybatis核心配置文件中

===>程序员自己控制处理的提交和回滚

在测试类中, 取出对象的时候, 可以设置成自动提交

  • sqlSession = factory.openSession(); ===>默认是手工提交事务,设置为false也是手工提交事务,如果设置为true,则为自动提交.
  • sqlSession = factory.openSession(true); ===>设置为自动提交,在增删改后不需要commit();

缓存

MyBatis框架提供两级缓存,一级缓存和二级缓存.默认开启一级缓存.

我们有专门的缓存框架redis

缓存就是为了提高查询效率

使用缓存后, 查询的流程 :

查询时先到缓存里查,如果没有则查询数据库,放缓存一份,再返回客户端.下次再查询的时候直接从缓存返回,不再访问数据库.如果数据库中发生commit()操作,则清空缓存.

一级缓存使用的是SqlSession的作用域,同一个sqlSession共享一级缓存的数据.
二级缓存使用的是mapper的作用域,不同的sqlSession只要访问的同一个mapper.xml文件,则共享二级缓存作用域.

ORM

ORM(Object Relational Mapping):对象关系映射

java语言中以对象的方式操作数据,存到数据库中是以表的方式进行存储,对象中的成员变量与表中的列之间的数据互换称为映射.整个这套操作就是ORM.

持久化的操作:将对象保存到关系型数据库中 ,将关系型数据库中的数据读取出来以对象的形式封装


文章作者: 冬瓜冬瓜排骨汤
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 冬瓜冬瓜排骨汤 !
  目录