MyBatis

以前的流程(功能简单,sql写在了Java代码内)

  1. 编写sql
  2. 预编译
  3. 设置参数
  4. 执行sql
  5. 封装结果

Mybaties会实现sql和编码分离写在配置文件内、sql由开发人员控制 是一个半自动化工具轻量级的框架

pom.xml

<?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>org.example</groupId>
    <artifactId>Mybaits</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>mybatis-01</module>
    </modules>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.7</version>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.2.0</version>
        </dependency>
    </dependencies>
        <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
</project>
<?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>
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    <typeAliases>
        <typeAlias type="Student" alias="Student"></typeAlias>
    </typeAliases>
    <environments default="dev">
        <environment id="dev">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&amp;serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
<!--        <package name="com.jian.java"></package>-->
<!--        <mapper resource="com/jian/java/StudentMapper.xml"></mapper>-->
        <package name="com.jian.java"></package>
<!--        <mapper class="StudentMapper"></mapper>-->
    </mappers>
</configuration>
<?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">
    <!--
        separator:表示分隔符
        <foreach collection="" separator="," open="(" close=")" index="" item="a"></foreach>
    -->
<!--    <select id="getALl" resultType="com.jian.java.Student">-->
<!--        select * from students where-->
<!--        <if test="sno!=null and sno.trim()!='' ">-->
<!--            sno=#{id}-->
<!--        </if>-->
<!--where只会去掉第一个出现的多出来的and  所以and写前面-->
<!--        <where>-->
<!--            <if test=""></if>-->
<!--        </where>-->

<!--
prefix="" trim整个拼串后的前缀
prefixOverrides="" 去掉前面多余的字符串
suffix=""
suffixOverrides=""
-->
<!--<trim prefix="where" prefixOverrides="and" suffixOverrides="and">-->
<!--    -->
<!--</trim>-->
<!--<choose>-->
<!--    <when test=""></when>-->
<!--    <otherwise></otherwise>-->
<!--</choose>-->

<!--
set标签可以去掉内容里多出来的逗号  where和它不用写 where和set
-->
<!--    </select>-->

    <select id="getMap" resultType="map">
        select * from students
    </select>

<!--    <update id="update" parameterType="student">-->
<!--    update students-->
<!--        <set>-->
<!--            <if test="sno!=null">age=#{age+1}</if>-->
<!--        </set>-->
<!--        where sno=#{sno}-->
<!--    </update>-->
<!--<select id="getUser" resultType="student">-->
<!--    select * from students-->
<!--</select>-->
<!--  可以将OGNL表达式的值绑定到一个遍量  方便引用  -->

<!--    <select id="">-->
<!--        <bind name="" value="'%'+lastname+'%'"/>-->
<!--    <include refid=""><property ></></include>-->
<!--    </select>-->
<!--<sql id="">-->
<!--  ${取出include定义的属性值}  -->
<!--</sql>-->
import com.jian.java.Student;
import com.jian.java.StudentMapper;
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 java.io.IOException;
import java.io.InputStream;

/**
 * @author Jiange
 * @create 2021-04-20-14:15
 */

/**
 * 在有多个参数的时候 会被封装成map  key就是param1~paramn  value就是我们传入的参数值
 * 对于传入的参数是List或者数组的时候 也会封装成map  key就是Collection 就是collection List就是list
 * 数组的key就是array
 * @Param("id") int id 这样时key就是id
 * 或者我们可以直接传入一个map #{key}就可以取出值
 */
public class Mytest {
    @Test
    public void test1() throws IOException {
        //根据配置文件创建工厂对象
        String resource = "mybatis.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取sqlsession实例、能直接执行已经映射的sql语句
        SqlSession sqlSession = sqlSessionFactory.openSession();//sqlsession代表和数据库的一次会话 用完关闭 不是线程安全的  每次使用都要重新获取 不能放在类的属性内

        System.out.println(sqlSession);

        //第一个参数是sql的唯一标识
        try{
            Student selectstu = sqlSession.selectOne("com.jian.java.selectstu",1);
            System.out.println(selectstu);
        }finally {
            sqlSession.close();
        }
    }

    @Test
    public void test2() throws IOException {
        String source = "mybatis.xml";
        InputStream inputStream = Resources.getResourceAsStream(source);
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = build.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);//会为接口自动创建创建一个代理对象

        Student byId = mapper.getById(1);

        System.out.println(byId);//com.jian.java.Student{Sno='1', Sname='李子建', sex='男'}
    }

    @Test
    public void test3() throws IOException {
        String source = "mybatis.xml";
        InputStream resourceAsStream = Resources.getResourceAsStream(source);
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = build.openSession();//不会自动提交

        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //mybatis允许的增删改直接定义以下类型返回值 integer  long Boolean  void  记得要手动提交  
//        mapper.add(new Student("8","尚硅谷","男"));
        mapper.delete("8");
        sqlSession.commit();
        sqlSession.close();
    }
}

@Test
    public void test4() throws IOException {
        String resource = "mybatis.xml";
        InputStream resourceAsStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = build.openSession();

        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

//        List<Student> all = mapper.getAll();
//        all.forEach(System.out::println);

//        Map<String, Object> returnMap = mapper.getReturnMap("2");
//        System.out.println(returnMap);

        Map<Integer, Student> stuMap = mapper.getStuMap();
        System.out.println(stuMap);
    }

//    mybatis的两 个默认的内置参数
//    _parameter:代表整个参数
//    _databaseID:

    @Test
    public void test1(){
        SqlSession sqlSession = get();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        List<Student> user = mapper.getUser();
        user.forEach(System.out::println);
    }



/**
     * mybatis有两级缓存
     * 一级缓存: 本地缓存
     *      与数据库同一次会话期间查询到数据会放在本地缓存中 SqlSession级别的缓存
     *      以后如果要是获取相同的数据、直接从缓存里面拿  不用再去查询数据库
     *      是一直开启的没法关闭
     *
     *      失效情况:
     *          换了一个SqlSession
     *          SqlSession相同查询语句不同
     *          SqlSession相同、查询语句相同、两次查询期间执行了增删改操作
     *          手动清楚了一级缓存的内容        sqlSession.clearCache();
     * 二级缓存: 全局缓存  基于namespace的缓存 一个namespace对应一个二级缓存
     *      工作机制
     *          一个会话查询一条数据这个会话就会被放到当前的一级缓存中
     *          如果会话关闭一级缓存就会被缓存到 二级缓存  新的查询就可以参照二级缓存里的内容
     *          不同的namespace查出的数据就会被放在自己对应的缓存(map中)
     *          查出的数据会被默认被放在一级缓存  只有会话提交或者关闭后 才会被放到二级缓存
     *      使用:
     *          开启耳机缓存的设置 <setting name="cacheEnabled" value="true"/>  默认是开启的
     *          去mapp.xml配置二级缓存  <cache></cache>
     *              <cache eviction="" flushInterval="" type="" size="" readOnly="" blocking=""></cache>
     *          eviction:缓存的回收策略:
     *          flushInterval:缓存刷新的间隔
     *              缓存多长时间清空一次、默认不清空  可以设置一个毫秒值
     *          readOnly:是否只读
     *              true:mybatis认为所有的缓存中获取数据的操作只是只读操作、不会修改数据
     *                      为了加快速度 会将缓存里的数据的引用交给用户 不安全
     *              false:mybatis会把缓存里的数据克隆一份  利用序列化和反序列化  安全  速度慢  默认就是false
     *          size表示缓存能放多少个元素
     *          type:指定自定义缓存的全类名
     *          所有的类要实现序列化接口
     *
     *          注意要使用同一个 sqlSessionFactory
     *          查询了的数据记得要提交事务 或者关闭连接
     *          每一个select标签都有 useCache  默认是true  false设置的是关闭二级缓存  flushCache默认是false 功能和下面这个一样
     *          增删改标签有一个flushCache有一个属性  默认是true  表示执行后会清除缓存  一级和二级缓存都会清除
     *          sqlSession.clearCache();只会清除当前session的一级缓存
     *          localCacheScope、设置一级缓存的  取值 STATEMENT禁用一级缓存  session表示会存在会话缓存  默认session
     */

@Test
    public void test1(){
        SqlSession sqlSession = get().openSession();

        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> all = mapper.getAll();
//        sqlSession.commit();
        List<Student> all1 = mapper.getAll();
        System.out.println(all == all1);//true/false  这就是一级缓存 直接从缓存里拿的 不要提交事务 提交了 就是false
        all.forEach(System.out::println);

//        int delete = mapper.delete("6");
//        System.out.println(delete);
//
//        sqlSession.commit();
//        sqlSession.close();
    }

<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"/>
    <select id="getAll" resultType="student" useCache="true">
        select * from students where sno = 1
    </select>

/**
     *  SqlSessionFactory
     *      build->parse->将所有的config保存到一个对象 mapper也是
     *      解析文件的每一个信息保存在configuration  返回configuration的DefaultSqlSessionFactory
     *      MappedStatement 代表一个sql的详细信息
     *  sqlsession
     *      返回DefaultSqlSession 包含Executor和configuration;这一步会创建Executor
     *  代理类接口对象
     *      getMapper  使用MapperProxyFactory创建一个MapperProxy的代理对象 代理对象包含了DefaultSqlSession(包含Executor)
     *    
     *  执行增删改查:
     *      调用invoke  判断增删改查类型  包装参数 即使是查询单个 也会调用selectList的第一个  最后还是会调用execute.query
     *      查出来就会保存到本地缓存
     *      
     *      
     *      总结:
     *          1. 根据配置文件初始化出Configuraction对象
     *          2. 创建DefaultSqlSession对象 包含Configuraction和Executor(根据配置文件的defaultExecutor)
     *          3. 根据getMapper得到代理对象 对象里有(DefaultSqlSession)
     *          4. 增删改查  会创建StateMent对象也会同时创建statementHandler 也会常见ParameterHandler
     *              和ResultSetHandler 
     *              ParameterHandler处理预编译参数以及设置参数值
     *          5. 使用ResultSetHandler封装结果
     * 插件原理:
     *              四个处理器 创建时 都会被拦截器包装以后返回  插件可以为四个处理器创建出代理对象  AOP编程
     *              代理对象就可以拦截四个对象每一个执行
     *
     *              插件的编写、
     *                  1.编写Interceptor的实现类
     *                  2.注解完成插件签名
     *                  3.将写好的插件注册到全局配置文件
     *              多插件会逆序调用
     */

package com.jian.java;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;

import java.beans.Statement;
import java.util.Properties;

/**
 * @author Jiange
 * @create 2021-04-23-12:52
 */
//告诉拦截那个对象的哪个方法
@Intercepts(
        {
                @Signature(type = StatementHandler.class,method = "parameterize",args = java.sql.Statement.class)
        }
)
public class  MyPlugin implements Interceptor {
    //拦截目标对象的方法执行
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //执行目标方法
        Object proceed = invocation.proceed();
        System.out.println("invocation"+invocation.getMethod());
        //返回执行后的返回值
        return proceed;
    }


    //包装目标对象  为目标对象创建一个代理对象
    @Override
    public Object plugin(Object o) {
        Object wrap = Plugin.wrap(o, this);
        System.out.println("plugin:"+o);
        //返回当前处理器对象的代理对象
        return wrap;
    }

    //将插件注册时的property设置进来
    @Override
    public void setProperties(Properties properties) {
        System.out.println(properties);
    }
}

package com.jian.java;

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * @author Jiange
 * @create 2021-04-23-15:33
 */
public class MyTypeHandler implements TypeHandler {
    /**
     * 定义当前的数据如何保存到数据库内
     * @param preparedStatement
     * @param i
     * @param o
     * @param jdbcType
     * @throws SQLException
     */
    @Override
    public void setParameter(PreparedStatement preparedStatement, int i, Object o, JdbcType jdbcType) throws SQLException {
        preparedStatement.setString(i,o.getCode());
    }

    @Override
    public Object getResult(ResultSet resultSet, String s) throws SQLException {
        return null;
    }

    @Override
    public Object getResult(ResultSet resultSet, int i) throws SQLException {
        return null;
    }

    @Override
    public Object getResult(CallableStatement callableStatement, int i) throws SQLException {
        return null;
    }
}

    @Test
    public void test5(){
        //批量操作
        SqlSessionFactory sqlSessionFactory = get();

        //可以批量操作的sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
    }
    /**
     * statementType="CALLABLE"
     * {call 名字()}
 *         <typeHandlers>
     *         <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType=""></typeHandler>
     *     </typeHandlers>
     */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值