mybatis_du笔记详细版1

1.mybatis概述

ORM:对象关系映射

O:object,java中的类对象

R:关系型数据库

M:mapper映射

mybatis是一个半自动的ORM框架,因为sql语句是需要自己编写的

Hibernate是一个全自动的ORM框架,sql语句可以自动生成

 mybatis框架的特点

支持定制化sql,存储过程,基本映射以及高级映射

避免了几乎所有的JDBC代码中手动设置参数以及获取结果

支持XML开发,也支持注解开发(为了保证sql的灵活,一般使用xml)

将接口和java中的pojo映射成数据库中的记录

体积小,一个mybatis jar包 和一个连接jar包,两个配置文件(核心配置和jdbc)

完全做到sql解耦合

支持动态sql

2.开发第一个mybatis程序

开发步骤

第一步:打包方式jar

第二步:引入依赖 - mybatis依赖 - mysql驱动依赖

第三步:编写mybatis核心配置文件:mybatis-config.xml 注意: 第一:这个文件名不是必须叫做mybatis-config.xml,可以用其他的名字。只是大家都采用这个名字。 第二:这个文件存放的位置也不是固定的,可以随意,但一般情况下,会放到类的根路径下。 mybatis-config.xml文件中的配置信息不理解没关系,先把连接数据库的信息修改以下即可。 其他的别动。

第四步:编写XxxxMapper.xml文件 在这个配置文件当中编写SQL语句。 这个文件名也不是固定的,放的位置也不是固定,我们这里给它起个名字,叫做:CarMapper.xml 把它暂时放到类的根路径下。

第五步:在mybatis-config.xml文件中指定XxxxMapper.xml文件的路径: <mapper resource="CarMapper.xml"/> 注意:resource属性会自动从类的根路径下开始查找资源。

第六步:编写MyBatis程序。(使用mybatis的类库,编写mybatis程序,连接数据库,做增删改查就行了。)

在MyBatis当中,负责执行SQL语句的那个对象叫做什么呢? SqlSession SqlSession是专门用来执行SQL语句的,是一个Java程序和数据库之间的一次会话。

要想获取SqlSession对象,需要先获取SqlSessionFactory对象,通过SqlSessionFactory工厂来生产SqlSession对象。

怎么获取SqlSessionFactory对象呢? 需要首先获取SqlSessionFactoryBuilder对象。 通过SqlSessionFactoryBuilder对象的build方法,来获取一个SqlSessionFactory对象。 mybatis的核心对象包括:

SqlSessionFactoryBuilder SqlSessionFactory SqlSession SqlSessionFactoryBuilder --> SqlSessionFactory --> SqlSession

可以使用工具类来封装这一过程

 使用静态代码块的好处是,只需要在程序开始的时候获取一下就行了,不需要过多的获取

public class SqlSessionUtil {

    // 工具类的构造方法一般都是私有化的。
    // 工具类中所有的方法都是静态的,直接采用类名即可调用。不需要new对象。
    // 为了防止new对象,构造方法私有化。
    private SqlSessionUtil(){}

    private static SqlSessionFactory sqlSessionFactory;

    // 类加载时执行
    // SqlSessionUtil工具类在进行第一次加载的时候,解析mybatis-config.xml文件。创建SqlSessionFactory对象。
    static {
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /*public static SqlSession openSession(){
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // SqlSessionFactory对象:一个SqlSessionFactory对应一个environment,一个environment通常是一个数据库。
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
        SqlSession sqlSession = sqlSessionFactory.openSession();
        return sqlSession;
    }*/

    /**
     * 获取会话对象。
     * @return 会话对象
     */
    public static SqlSession openSession(){
        return sqlSessionFactory.openSession();
    }

}

关于第一个程序的小细节 * mybatis中sql语句的结尾";"可以省略。 Resources.getResourceAsStream 小技巧:以后凡是遇到resource这个单词,大部分情况下,这种加载资源的方式就是从类的根路径下开始加载。(开始查找) 优点:采用这种方式,从类路径当中加载资源,项目的移植性很强。项目从windows移植到linux,代码不需要修改,因为这个资源文件一直都在类路径当中。 

InputStream is = new FileInputStream("d:\\mybatis-config.xml"); 采用这种方式也可以。 缺点:可移植性太差,程序不够健壮。可能会移植到其他的操作系统当中。导致以上路径无效,还需要修改java代码中的路径。这样违背了OCP原则。

已经验证了: mybatis核心配置文件的名字,不一定是:mybatis-config.xml。可以是其它名字。 mybatis核心配置文件存放的路径,也不一定是在类的根路径下。可以放到其它位置。但为了项目的移植性,健壮性,最好将这个配置文件放到类路径下面。

InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config.xml");

ClassLoader.getSystemClassLoader() 获取系统的类加载器。 系统类加载器有一个方法叫做:getResourceAsStream 它就是从类路径当中加载资源的。

通过源代码分析发现上面的就等于这个: InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); 

CarMapper.xml文件的名字是固定的吗?CarMapper.xml文件的路径是固定的吗? 都不是固定的。 <mapper resource="CarMapper.xml"/> resource属性:这种方式是从类路径当中加载资源。 <mapper url="file:///d:/CarMapper.xml"/> url属性:这种方式是从绝对路径当中加载资源。

3.关于mybatis事务管理机制

在mybatis.xml文件中,可以通过配置<transactionManager type="JDBC"/>管理事务

type属性的值包括两个:JDBC(jdbc)       MANAGED(managed)

mybatis中提供了上述两种事务管理机制

jdbc事务管理器:

mybatis框架自己管理事务,采用自己原生的jdbc代码去管理事务:

       conn.setAutoCommit(false); 开启事务。

        业务处理

       conn.commit(); 手动提交事务

使用jdbc管理事务的话,低层创建事务管理器对象:jdbctransaction对象

如果通过工厂方法开启SqlSession会话的时候

SqlSession sqlSession = sqlSessionFactory.openSession(true);

表明不开启事务,这种方式在低层的源码中不会开启事务,在一个判断条件中跳过了 conn.setAutoCommit(false);语句。执行一条语句就会直接提交。

MANAGED事务管理器:

mybatis不再负责事务管理器,事务管理器交给其他容器来负责,例如spring

如果这个时候只有mybatis的情况下,就会没人管理事务,相当于不开启的状态 

4.mybatis的日志组件

mybatis常见的日志组件 

SLF4J(沙拉风):沙拉风是一个日志标准,其中有一个框架叫做logback,它实现了沙拉风规范。

LOG4J

LOG4J2

STDOUT_LOGGING ....

注意:log4j log4j2 logback都是同一个作者开发的。

其中STDOUT_LOGGING是标准日志,mybatis已经实现了这种日志

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

另外,mybatis的配置文件中有顺序存在,必须注意标签的顺序。

集成logback日志框架

 logback日志框架实现了slf4j标准。(沙拉风:日志门面。日志标准。)

第一步:引入logback的依赖。
 

<dependency>

<groupId>ch.qos.logback</groupId>

<artifactId>logback-classic</artifactId>

<version>1.2.11</version>

</dependency>

第二步:引入logback所必须的xml配置文件。 这个配置文件的名字必须叫做:logback.xml或者logback-test.xml,不能是其它的名字。 这个配置文件必须放到类的根路径下。不能是其他位置。 主要配置日志输出相关的级别以及日志具体的格式。

<?xml version="1.0" encoding="UTF-8"?>

<configuration debug="false">
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>[%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>

    <!--mybatis log configure-->
    <logger name="com.apache.ibatis" level="TRACE"/>
    <logger name="java.sql.Connection" level="DEBUG"/>
    <logger name="java.sql.Statement" level="DEBUG"/>
    <logger name="java.sql.PreparedStatement" level="DEBUG"/>

    <!-- 日志输出级别,logback日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR -->
    <root level="DEBUG">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILE"/>
    </root>

</configuration>

mybatis配置文件详解

1.首先是properties标签

这个标签是一个map集合类,都是String类型,可以用这种方式直接配置数据源,然后再下面环境配置的数据源的位置使用${jdbc.driver}的方式来引用value的值

    <properties>
<!--        这是其中的一个属性-->
        <property name="属性名" value="属性值"/>
        <property name="jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbc.url" value="jdbc:mysql://localhost:3306/powernode"/>
        <property name="jdbc.username" value="root"/>
        <property name="jdbc.password" value="root"/>
    </properties>

另一种方式是使用

 <!--resource,一定是从类路径下开始查找资源-->
    <properties resource="jdbc.properties" />

<!--从绝对路径当中加载资源。绝对路径怎么写?file:///路径-->
    <!--<properties url="file:///d:/jdbc.properties" />-->

2.然后是<typeAliases>标签,用于批量注册pojo类的名称,在mapper映射文件中可以直接使用类名的驼峰命名来代替全路径名称

<typeAliases>
        <package name="com.mybatis.pojo"/>
    </typeAliases>

3.settings标签 :用于打印日志,有好几种日志打印方式

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

4. environments标签

用于mybatis的环境使用,一般定义数据源和事务。可以有多个环境的定义,只需要更改default的值就可以更改环境的使用。

<!--default表示默认使用的环境。-->
    <!--默认环境什么意思?当你使用mybatis创建SqlSessionFactory对象的时候,没有指定环境的话,默认使用哪个环境。-->
    <environments default="powernodeDB">

        <!--其中的一个环境。连接的数据库是powernode-->
        <!--一般一个数据库会对应一个SqlSessionFactory对象。-->
        <!--一个环境environment会对应一个SqlSessionFactory对象-->
        <environment id="powernodeDB">
            <!--
                transactionManager标签:
                    1.作用:配置事务管理器。指定mybatis具体使用什么方式去管理事务。
                    2.type属性有两个值:
                        第一个:JDBC: 使用原生的JDBC代码来管理事务。
                            conn.setAutoCommit(false);
                            ....
                            conn.commit();
                        第二个:MANAGED:mybatis不再负责事务的管理,将事务管理交给其它的JEE(JavaEE)容器来管理。例如:spring
                    3. 大小写无所谓。不缺分大小写。但是不能写其他值。只能是二选一:
                        jdbc、managed
                    4. 在mybatis中提供了一个事务管理器接口:Transaction
                        该接口下有两个实现类:
                            JdbcTransaction
                            ManagedTransaction
                        如果type="JDBC",那么底层会实例化JdbcTransaction对象。
                        如果type="MANAGED",那么底层会实例化ManagedTransaction
            -->
            <transactionManager type="JDBC"/>
            <!--
                dataSource配置:
                    1.dataSource被称为数据源。
                    2.dataSource作用是什么?为程序提供Connection对象。(但凡是给程序提供Connection对象的,都叫做数据源。)
                    3.数据源实际上是一套规范。JDK中有这套规范:javax.sql.DataSource(这个数据源的规范,这套接口实际上是JDK规定的。)
                    4.我们自己也可以编写数据源组件,只要实现javax.sql.DataSource接口就行了。实现接口当中所有的方法。这样就有了自己的数据源。
                    比如你可以写一个属于自己的数据库连接池(数据库连接池是提供连接对象的,所以数据库连接池就是一个数据源)。
                    5.常见的数据源组件有哪些呢【常见的数据库连接池有哪些呢】?
                        阿里巴巴的德鲁伊连接池:druid
                        c3p0
                        dbcp
                        ....
                    6. type属性用来指定数据源的类型,就是指定具体使用什么方式来获取Connection对象:
                        type属性有三个值:必须是三选一。
                        type="[UNPOOLED|POOLED|JNDI]"
                        UNPOOLED:不使用数据库连接池技术。每一次请求过来之后,都是创建新的Connection对象。
                        POOLED:使用mybatis自己实现的数据库连接池。
                        JNDI:集成其它第三方的数据库连接池。

                        JNDI是一套规范。谁实现了这套规范呢?大部分的web容器都实现了JNDI规范:
                            例如:Tomcat、Jetty、WebLogic、WebSphere,这些服务器(容器)都实现了JNDI规范。
                        JNDI是:java命名目录接口。Tomcat服务器实现了这个规范。
            -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
                <!--提醒:正常使用连接池的话,池中有很多参数是需要设置的。设置好参数,可以让连接池发挥的更好。事半功倍的效果。-->
                <!--具体连接池当中的参数如何配置呢?需要反复的根据当前业务情况进行测试。-->
                <!--poolMaximumActiveConnections:连接池当中最多的正在使用的连接对象的数量上限。最多有多少个连接可以活动。默认值10-->
                <property name="poolMaximumActiveConnections" value="10"/>
                <!--每隔2秒打印日志,并且尝试获取连接对象-->
                <property name="poolTimeToWait" value="2000"/>
                <!--强行让某个连接空闲,超时时间的设置-->
                <property name="poolMaximumCheckoutTime" value="10000"/>
                <!--最多的空闲数量-->
                <property name="poolMaximumIdleConnections" value="5"/>
            </dataSource>

        </environment>

        <!--这是mybatis的另一个环境,也就是连接的数据库是另一个数据库mybatis-->
        <environment id="mybatisDB">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>

    </environments>

5.mappers标签

用于注册映射文件的位置,可以使用单独注册的mapper方式或者批量的包注册

<mappers>
        <mapper resource="CarMapper.xml"/>
<!--        <package name="com.mybatis.dao"/>-->
    </mappers>

5.使用javassist来动态生成类并实现方法

首先这个包在mybatis下import org.apache.ibatis.javassist.*;

首先有一个接口,里面有一些方法

 @Test
    public void testDaoImpl1() throws CannotCompileException, IllegalAccessException, InstantiationException {
//        获取类池
        ClassPool pool=ClassPool.getDefault();
//        制造类
        CtClass ctClass = pool.makeClass("com.bank.dao.impl.0AccountDaoImpl");
//        制造接口
        CtClass makeInterface = pool.makeInterface("com.bank.dao.AccountDao");
//        添加接口到类中
        ctClass.addInterface(makeInterface);
//        实现接口中的方法
        CtMethod method = CtMethod.make("public void delete(){ System.out.println(\"delete\");}", ctClass);
//        将方法添加到类中
        ctClass.addMethod(method);
//        在内存中生成类,同时加载到jvm中
        Class<?> aClass = ctClass.toClass();
//        通过反射机制创建对象
        AccountDao accountDao = (AccountDao) aClass.newInstance();
        accountDao.delete();
    }
}

这样就可以直接在内存中生成这个实现类的字节码文件,然后通过反射机制来创建接口对象来调用方法。

这是一个简单的实现类生成方法,mybatis可以帮你创建持久层接口的实现类,使用的是类似于这种创建在内存中的方式

**
 * 工具类:可以动态的生成DAO的实现类。(或者说可以动态生成DAO的代理类)
 * 注意注意注意注意注意!!!!!!:
 *      凡是使用GenerateDaoProxy的,SQLMapper.xml映射文件中namespace必须是dao接口的全名,id必须是dao接口中的方法名。
 * @author 动力节点
 * @version 1.0
 * @since 1.0
 */
public class GenerateDaoProxy { // GenerateDaoProxy是mybatis框架的开发者写的。

    /**
     * 生成dao接口实现类,并且将实现类的对象创建出来并返回。
     * @param daoInterface dao接口
     * @return dao接口实现类的实例化对象。
     */
    public static Object generate(SqlSession sqlSession, Class daoInterface){
        // 类池
        ClassPool pool = ClassPool.getDefault();
        // 制造类(com.powernode.bank.dao.AccountDao --> com.powernode.bank.dao.AccountDaoProxy)
        CtClass ctClass = pool.makeClass(daoInterface.getName() + "Proxy"); // 实际本质上就是在内存中动态生成一个代理类。
        // 制造接口
        CtClass ctInterface = pool.makeInterface(daoInterface.getName());
        // 实现接口
        ctClass.addInterface(ctInterface);
        // 实现接口中所有的方法
        Method[] methods = daoInterface.getDeclaredMethods();
        Arrays.stream(methods).forEach(method -> {
            // method是接口中的抽象方法
            // 将method这个抽象方法进行实现
            try {
                // Account selectByActno(String actno);
                // public Account selectByActno(String actno){ 代码; }
                StringBuilder methodCode = new StringBuilder();
                methodCode.append("public ");
                methodCode.append(method.getReturnType().getName());
                methodCode.append(" ");
                methodCode.append(method.getName());
                methodCode.append("(");
                // 需要方法的形式参数列表
                Class<?>[] parameterTypes = method.getParameterTypes();
                for (int i = 0; i < parameterTypes.length; i++) {
                    Class<?> parameterType = parameterTypes[i];
                    methodCode.append(parameterType.getName());
                    methodCode.append(" ");
                    methodCode.append("arg" + i);
                    if(i != parameterTypes.length - 1){
                        methodCode.append(",");
                    }
                }
                methodCode.append(")");
                methodCode.append("{");
                // 需要方法体当中的代码
                methodCode.append("org.apache.ibatis.session.SqlSession sqlSession = com.powernode.bank.utils.SqlSessionUtil.openSession();");
                // 需要知道是什么类型的sql语句
                // sql语句的id是框架使用者提供的,具有多变性。对于我框架的开发人员来说。我不知道。
                // 既然我框架开发者不知道sqlId,怎么办呢?mybatis框架的开发者于是就出台了一个规定:凡是使用GenerateDaoProxy机制的。
                // sqlId都不能随便写。namespace必须是dao接口的全限定名称。id必须是dao接口中方法名。
                String sqlId = daoInterface.getName() + "." + method.getName();
                SqlCommandType sqlCommandType = sqlSession.getConfiguration().getMappedStatement(sqlId).getSqlCommandType();
                if (sqlCommandType == SqlCommandType.INSERT) {

                }
                if (sqlCommandType == SqlCommandType.DELETE) {

                }
                if (sqlCommandType == SqlCommandType.UPDATE) {
                    methodCode.append("return sqlSession.update(\""+sqlId+"\", arg0);");
                }
                if (sqlCommandType == SqlCommandType.SELECT) {
                    String returnType = method.getReturnType().getName();
                    methodCode.append("return ("+returnType+")sqlSession.selectOne(\""+sqlId+"\", arg0);");
                }

                methodCode.append("}");
                CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
                ctClass.addMethod(ctMethod);
            } catch (Exception e) {
                e.printStackTrace();
            }

        });

        // 创建对象
        Object obj = null;
        try {
            Class<?> clazz = ctClass.toClass();
            obj = clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

}

例如上述这种代理方式,只需要获取接口的字节码文,然后就可以通过反射机制获取接口中的方法信息。然后可以构建出接口的实现类。

接口中的方法具体的内容则由mapper.xml文件写,解析这个文件的时候需要根据id来寻找对应的信息,所以在使用mybatis的时候必须把namespace的值设置为接口的全路径名称,sql语句的id设置为方法的名称。通过这种方法来为你在内存中创建出一个实现类,本质山还是调用sqlsession的操作数据库方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MyBatis PageHelper是一个用于实现分页查询的插件,它可以帮助我们快速实现分页功能,并且与Mapper.xml完全解耦,避免了直接编写分页SQL的麻烦。在使用MyBatis PageHelper时,可以根据不同的情况进行配置。 如果你使用的是Spring Boot,可以直接配置几个属性来启用MyBatis PageHelper。在application.properties或application.yml文件中,添加以下配置项: ``` mybatis.configuration-properties.helperDialect=mysql mybatis.configuration-properties.offsetAsPageNum=true mybatis.configuration-properties.rowBoundsWithCount=true mybatis.configuration-properties.reasonable=true mybatis.configuration-properties.mapper-locations=mybatis/mapper/*.xml ``` 其中,helperDialect指定了数据库的方言,offsetAsPageNum设置为true表示使用RowBounds分页方式,rowBoundsWithCount设置为true表示查询总数时会同时执行count查询,reasonable设置为true表示当pageNum<=0或pageNum>pages时会自动修正为合理的值,mapper-locations指定了Mapper.xml文件的位置。 另外,如果你使用的是Spring Boot,还可以直接引入pagehelper-spring-boot-starter依赖,它会自动配置PageHelper,省去了许多不必要的配置。 ```xml <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.12</version> </dependency> ``` 通过以上配置,你就可以在MyBatis中使用PageHelper来实现分页查询了。 #### 引用[.reference_title] - *1* [【Mybatis】使用PageHelper进行分页查询](https://blog.csdn.net/Flying_Ape/article/details/128098911)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Mybatis分页插件——PageHelper快速入门](https://blog.csdn.net/weixin_52850476/article/details/124802877)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值