Explicación detallada de Mybatis (súper completa)

Tabla de contenido:

1. Primeros pasos con MyBatis

1. Qué es MyBatis

​ MyBatis es un excelente marco de capa de persistencia que admite SQL personalizado, procedimientos almacenados y mapeo avanzado. MyBatis elimina casi todo el código JDBC y el trabajo de establecer parámetros y obtener conjuntos de resultados. MyBatis puede configurar y mapear tipos primitivos, interfaces y Java POJO (Plain Old Java Objects, Plain Old Java Objects) como registros en la base de datos a través de XML simple o anotaciones.

2, MyBatis, Hibernate y JDBC

  1. En comparación con Hibernate, MyBatis tiene una encapsulación más baja que Hibernate, pero tiene un rendimiento excelente, un tamaño pequeño, fácil de aprender y una amplia aplicación.

  2. Comparado con JDBC, MyBatis reduce la cantidad de código en más de un 50% y cumple con los requisitos de alta concurrencia y alta respuesta

3. Ventajas y desventajas

3.1 Ventajas

  • MyBatis es gratuito y de código abierto.
  • En comparación con JDBC, la cantidad de código se reduce en más del 50 %.
  • MyBatis es el framework de persistencia más simple, pequeño y fácil de aprender.
  • MyBatis es bastante flexible y no impondrá ningún impacto en el diseño existente de la aplicación o la base de datos.SQL está escrito en XML, separado del código lógico del programa, lo que reduce el acoplamiento, facilita la gestión unificada y la optimización, y mejora la reutilización del código.
  • Proporciona etiquetas XML y admite la escritura de sentencias SQL dinámicas.
  • Proporciona etiquetas de asignación para admitir la asignación de relaciones de campo ORM entre objetos y bases de datos.
  • Se admiten procedimientos almacenados. MyBatis encapsula SQL en forma de procedimientos almacenados, lo que puede mantener la lógica comercial fuera de la base de datos, mejorar la portabilidad de las aplicaciones y hacerlas más fáciles de implementar y probar.

3.2 Desventajas

  • Escribir sentencias SQL requiere mucho trabajo, lo que requiere que los desarrolladores tengan una base sólida para escribir sentencias SQL.
  • Las declaraciones de SQL dependen de la base de datos, lo que da como resultado una portabilidad deficiente de la base de datos y la base de datos no se puede reemplazar a voluntad.

3.3 Escenarios de uso

​ MyBatis se centra en el propio SQL y es una solución de capa DAO lo suficientemente flexible. Es adecuado para proyectos con requisitos de alto rendimiento y cambios frecuentes en los requisitos, como proyectos de Internet.

4. Instalación

Para usar MyBatis, simplemente coloque mybatis-x.x.x.jarel archivo en el classpath (classpath).Si usa Maven para construir el proyecto, debe colocar el siguiente código de dependencia en el archivo pom.xml

1. Por ejemplo, en un proyecto Maven, importa las dependencias de la versión MyBatis3.5.2

<!--MyBatis依赖-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
</dependency>
<!--数据库依赖-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>

2. El primer programa MyBatis

1. Cree SqlSessionFactory a partir de XML

​ Cada aplicación basada en MyBatis se centra en una instancia de SqlSessionFactory. SqlSessionFactoryBuilder puede obtener una instancia de SqlSessionFactory. SqlSessionFactoryBuilder puede crear una instancia de SqlSessionFactory a partir de un archivo de configuración XML o una instancia de configuración preconfigurada.

1.1 Configuración XML

​El archivo de configuraciónmybatis-config.xml contiene la configuración central del sistema MyBatis, incluida la fuente de datos (DataSource) para obtener la instancia de conexión de la base de datos y el administrador de transacciones (TransactionManager) que determina el alcance de la transacción y el método de control. Los detalles del archivo de configuración XML se discutirán más adelante, aquí hay un ejemplo simple:

<?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配置内容时,有顺序限制-->
<configuration>
    <!--mybatis环境,default属性指定一个环境-->
    <environments default="development">
        <!--id属性自定义的环境唯一标识符-->
        <environment id="development">
            <!--指定使用jdbc事务管理-->
            <transactionManager type="JDBC"/>
            <!--使用mybatis内部带连接池功能的数据源-->
            <dataSource type="POOLED">
                <!--获取配置驱动-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--获取配置url-->
                <property name="url" value="jdbc:mysql://localhost:3306/demo?useUnicode=true&amp;characterEncoding=utf8"/>
                <!--获取配置账号-->
                <property name="username" value="root"/>
                <!--获取配置密码-->
                <property name="password" value="112112"/>
            </dataSource>
        </environment>
    </environments>
    <!--映射器,映射器的 XML 映射文件包含了 SQL 代码和映射定义信息-->
    <mappers>
        <!--使用相对于类路径的资源引用  这是相对于类路径中-->
		<mapper resource="mapper/UserMapper.xml"/>
        <!--<mapper resource="com/hqyj/mapper/UserMapper.xml"/>-->
    </mappers>
</configuration>

1.1.1 Precauciones

1. Preste atención a la declaración del encabezado XML, que se utiliza para verificar la exactitud del documento XML.

2. El elemento de mapeadores contiene un conjunto de mapeadores (mapper), y los archivos de mapeo XML de estos mapeadores contienen código SQL e información de definición de mapeo

3. Para los mapeadores, al <mapper resource="mapper/UserMapper.xml"/>importar archivos XML, los archivos XML están bajo los recursos del proyecto maven o el siguiente contenido debe importarse en el archivo pom.xml

<build>
    <!--resources配置解决mybatis 的mapperXml配置在java路径不被扫描的问题 -->
    <resources>
        <resource>
            <directory>src/main/java</directory>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
        </resource>
    </resources>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <!--跳过测试 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <skipTests>true</skipTests>
            </configuration>
        </plugin>
    </plugins>
</build>

1.2 Obtener SqlSessionFactory

// 读取配置文件mybatis-config.xml
InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
// 根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);

1.3 Diseñar tablas de bases de datos

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` int(255) NULL DEFAULT NULL,
  `state` int(255) NULL DEFAULT 1,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

INSERT INTO `user` VALUES (1, 'admin', '111', 20, 1);
INSERT INTO `user` VALUES (2, '王五', '789', 24, 1);
INSERT INTO `user` VALUES (3, '小王', '123', 88, 1);

1.4 Escribir JavaBean

Primero, descargue el complemento Lombok en IDEA

Luego importe dependencias en pom.xml

<!--Lombok依赖-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.6</version>
</dependency>

Finalmente, use anotaciones en lugar de setters, getters, toString y constructores.

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    
    
    private int id;
    private String name;
    private String password;
    private int age;
    private int deptId;
    private int state;
}

1.5 Escribir UserMapper

<?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.hqyj.mapper.UserMapper">
    <select id="getUserList" resultType="com.hqyj.pojo.User">
        select * from `user`
    </select>
</mapper>

1.6 Pruebas

// 读取配置文件mybatis-config.xml
InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
// 根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
// 通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 执行SQL---方式一
// SqlSession执行文件中定义的SQL,并返回映射结果,参数可以直接输入方法名
// List<User> userList = sqlSession.selectList("com.hqyj.cl.mapper.UserMapper.getUserList");
// 执行SQL---方式二
// 通过SqlSession对象获取StudentMapper的代理对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
// 使用代理mapper对象查询全部的用户信息
List<Student> studentList = mapper.selectAll();
// 输出内容
System.out.println(userList);

1.7 #{} y ${}

#{}Es seguro pasar valor en el método, y actúa como marcador de posición, ¿cuál es un marcador de posición de parámetro?, es decir, precompilación de sql, que puede evitar la inyección de sql

${}El reemplazo de cadenas, es decir, el empalme de sql, no puede evitar la inyección de sql

1.7.1 Caso de inyección

Aviso:

El método de uso ${}obtendrá el contenido de la propiedad de configuración en jdbc.properties, así que preste atención

​ Si hay más de o igual a 2 parámetros en la interfaz de UserMapper, entonces hay 3 formas de resolver el problema de que no se pueden encontrar los parámetros

1. Encapsular en un método de recopilación de mapas (sin mencionar que por ahora es más engorroso)

2. Encapsular en un objeto de clase pojo correspondiente (los parámetros del método de inicio de sesión se reemplazan directamente con objetos de Usuario)

3. Use la anotación @Param para especificar el nombre del parámetro para ajustar el método de interfaz del mapeador

​ login(@Param(“nombre de usuario”)String nombre de usuario,@Param(“contraseña”)String contraseña)

​Recomendación oficial: utilice anotaciones si el número de parámetros es inferior a 5 y utilice objetos si el número de parámetros es superior a 5

List<Student> login(@Param("username")String username,@Param("password")String password);
<select id="login" resultType="com.hqyj.cl.pojo.Student">
    select * from `student` where username='${username}' and password='${password}'
</select>
public class TestStudentDao {
    
    
    public static void main(String[] args) throws IOException {
    
    
        InputStream resourceAsStream = Resources.getResourceAsStream("config/mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //可以调整login参数只有username以及mapper的sql 发现可以查出,但是2个参数不行
        List<Student>  student = mapper.login("admin","111222' or '1'='1");
        System.out.println(student);
    }
}

3. Objetos centrales

MyBatis tiene tres elementos básicos:

  • Interfaces y clases principales
  • Archivo de configuración principal de MyBatis (mybatis-config.xml)
  • Archivo de mapeo SQL (mapper.xml)

Las interfaces principales y las clases de MyBatis son las siguientes

                           bulid()                        openSession()
SqlSessionFactoryBuilder  --------->  sqlSessionFactory  --------------->  sqlSession 

Cada aplicación de MyBatis se centra en una instancia de un objeto SqlSessionFactory.

Primero obtenga el objeto SqlSessionFactoryBuilder, que se puede construir de acuerdo con el archivo de configuración XML o la instancia de la clase de configuración.

Luego obtenga el objeto SqlSessionFactory, que se puede obtener a través del objeto SqlSessionFactoryBuilder.

Con el objeto SqlSessionFactory, puede obtener la instancia de SqlSession. El objeto SqlSession contiene completamente todos los métodos para ejecutar operaciones SQL con la base de datos como fondo, y la instrucción SQL asignada se puede ejecutar directamente con esta instancia.

**Debe tenerse en cuenta que:**Cada subproceso tiene su propia instancia de SqlSession, y la instancia de SqlSession no se puede compartir ni es segura para subprocesos. Por lo tanto, el ámbito de SqlSession está dentro del ámbito de la solicitud o del cuerpo del método.

Solicitud de mención Recordar la redirección y el reenvío aprendidos en la etapa anterior. La redirección no es la misma solicitud, sino dos solicitudes, y el alcance de la solicitud no se compartirá.

1, SqlSessionFactoryBuilder

SqlSessionFactoryBuilder genera SqlSessionFactory en función de la información de configuración o el código, y proporciona múltiples sobrecargas del método build(), que llaman al mismo método de firma, a saber:

build(Reader reader, String environment, Properties properties)

Dado que el entorno de parámetros y las propiedades pueden ser nulos, para eliminar métodos duplicados, en realidad solo hay tres métodos sobrecargados de la siguiente manera:

  • build (InputStream inputStream, entorno de cadena, propiedades de propiedades)
  • build (lector lector, entorno de cadena, propiedades de propiedades)
  • construir (Configuración de configuración)

A través del análisis anterior, se encuentra que la información de configuración se puede proporcionar al método build() de SqlSessionFactoryBuilder en tres formas, a saber, InputStream (flujo de bytes), Lector (flujo de caracteres) y Configuración (clase).

Dado que tanto el flujo de bytes como el flujo de caracteres pertenecen a la forma de leer archivos de configuración, es fácil pensar en dos formas de crear una SqlSessionFactory, a saber: leer archivos de configuración XML y escribir código. Generalmente se usa para construir SqlSessionFactory en forma de archivos de configuración XML, de modo que, por un lado, se puede evitar la codificación dura y, por otro lado, es conveniente que el personal de configuración futuro modifique y evite la compilación repetida de código.

1.1 Ciclo de vida y alcance de SqlSessionFactoryBuilder

La característica más importante de SqlSessionFactoryBuilder es que se desecha después de su uso. Después de crear el objeto SqlSessionFactory, esta clase no existe porque el mejor alcance de SqlSessionFactoryBuilder existe en el cuerpo del método, es decir, las variables locales.

2, SqlSessionFactory

SqlSessionFactory es una interfaz de fábrica en lugar de una clase real, su tarea es crear SqlSession, todas las aplicaciones de MyBatis están centradas en la instancia de SqlSessionFactory, y la instancia de SqlSessionFactory se puede obtener a través del objeto SqlSessionFactoryBuilder

2.1 Ciclo de vida y alcance de SqlSessionFactory

Una vez que se crea un objeto SqlSessionFactory, persiste en toda la aplicación. No hay motivo para destruirlo o volver a crearlo, y no se recomienda crear SqlSessionFactory varias veces durante la ejecución de una aplicación. Por lo tanto, el mejor alcance de SqlSessionFactory es Application, que existe con el ciclo de vida de la aplicación. Este modo "existe durante todo el tiempo de ejecución de la aplicación, y solo hay una instancia de objeto" es el llamado modo singleton (que se refiere a una y solo una instancia durante el tiempo de ejecución).

3, sesión SQL

SqlSession es un objeto que se utiliza para realizar operaciones persistentes, similar a Connection en JDBC. Proporciona todos los métodos necesarios para ejecutar comandos SQL en la base de datos y puede ejecutar directamente instrucciones SQL asignadas a través de la instancia de SqlSession.

Hay dos usos principales de SqlSession:

  1. Consigue un mapeador. Deje que el asignador encuentre el SQL correspondiente a través del espacio de nombres y el nombre del método, envíelo a la base de datos y devuelva el resultado después de la ejecución.
  2. Ejecute SQL directamente a través de "espacio de nombres (namespace) + id de SQL", sin obtener un mapeador.

3.1 Ciclo de vida y alcance de SqlSession

SqlSession corresponde a una sesión de base de datos. Dado que la sesión de la base de datos no es permanente, el ciclo de vida de SqlSession no es permanente y el objeto SqlSession debe crearse cada vez que se accede a la base de datos. Se recomiendan métodos de encapsulación para recuperar recursos.

4. Archivo de configuración

En el primer programa de MyBatis, hemos escrito el archivo de configuración de MyBatis mybatis-config.xml, hablemos en detalle del contenido del archivo de configuración

1. Estructura del archivo de configuración de MyBatis

**Precauciones: **Los nodos de elementos en el archivo mybatis-config.xml tienen un cierto orden, y las posiciones de los nodos deben ordenarse de acuerdo con las posiciones anteriores, de lo contrario habrá errores de compilación.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 配置 -->
    <properties /><!-- 属性 -->
    <settings /><!-- 设置 -->
    <typeAliases /><!-- 类型命名 -->
    <typeHandlers /><!-- 类型处理器 -->
    <objectFactory /><!-- 对象工厂 -->
    <plugins /><!-- 插件 -->
    <environments><!-- 配置环境 -->
        <environment><!-- 环境变量 -->
            <transactionManager /><!-- 事务管理器 -->
            <dataSource /><!-- 数据源 -->
        </environment>
    </environments>
    <databaseIdProvider /><!-- 数据库厂商标识 -->
    <mappers /><!-- 映射器 -->
</configuration>

1.1 etiqueta de configuración

El elemento de configuración es el nodo raíz de todo el archivo de configuración XML, y su rol es equivalente al de administrador de MyBatis, en él se almacenará toda la información de configuración de MyBatis.

1.2 etiqueta de propiedades

La etiqueta de propiedades puede especificar un archivo de propiedades externo (dbconfig.properties) a través del atributo de recurso, o puede configurarse a través del subelemento de propiedades. como sigue

<!--驱动-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--获取连接对象地址-->
<property name="url" value="jdbc:mysql://localhost:3306/demo?useUnicode=true&amp;characterEncoding=utf8"/>
<!--数据库用户名-->
<property name="username" value="root"/>
<!--数据库密码-->
<property name="password" value="112112"/>

Haga referencia a las variables anteriores en el nodo de entornos.

<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
        </dataSource>
    </environment>
</environments>

A partir de la versión 3.4.2 de mybatis, la función de proporcionar marcadores de posición de atributo (conocimiento)
está desactivada de forma predeterminada. Habilite manualmente la configuración
1 y habilite la configuración. <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>
Si usa el carácter ":" en el nombre del atributo (como: db: nombre de usuario), o en El operador ternario de la expresión OGNL se usa en el mapeo de SQL
(como: nombre de la tabla! = nulo? nombre de la tabla: 'constantes globales'), es necesario establecer un atributo específico para modificar el carácter separando el nombre del atributo y el valor por defecto 2. Configuración de Otra configuración' < propertyname = " org . apache . ibatis . parsing . Property Parser . default − value − separator " value = " ? : " / > ' 3. Modificar y volver a la propiedad de la cuenta ' < propertyname = " username " value = " {tableName != null ? tableName : 'global_constants'}), debe establecer propiedades específicas para modificar los caracteres que separan el nombre de la propiedad y el valor predeterminado 2. Establezca otros configuración `<property name="org.apache.ibatis.parsing.PropertyParser .default-value-separator" value="?:"/>` 3. Modifique la propiedad de la cuenta` <property name="username" value="¡ Nombre de la tabla ! _ _=nulo ? _ _ nombre de la mesa _ _ _:global _ _ _ _doo s t an t s _ ), debe establecer propiedades específicas para modificar el carácter que separa el nombre de la propiedad y el valor predeterminado2, establezca otras configuraciones'<propiedad de ellos _ _ _ _ _=" or g . a p a c h e . iba ti s . p a rsing . P ro p er t y P a rser . def a u lt _ _ _ _ _valor _ _ _ _se p a r a t o " valor " _ _ _=" ?:"/>'3.Modificar y volver al número de cuenta inmueble '<propiedad de ellos _ _ _ _ _=valor de " nombre de usuario " _ _ _ _=" {username?:root}"/> 4、这样,如果没有设置`, es usar root

1.3 pestaña de configuración

​ La etiqueta de configuración se usa para configurar el comportamiento del tiempo de ejecución de MyBatis. Puede afectar profundamente el funcionamiento subyacente de MyBatis. Generalmente, no se requiere mucha configuración y su valor predeterminado se puede usar en la mayoría de los casos. En la mayoría de los casos, utilícelo para configurar registros, habilitar la asignación automática de reglas de nomenclatura de joroba y habilitar la memoria caché de segundo nivel (habilitada de forma predeterminada).

1.3.1 Habilitar la asignación automática de reglas de nomenclatura de casos de camellos

<settings>
    <!-- 开启驼峰命名规则 -->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

1.3.2 Registro de configuración

<settings>
    <!-- 配置log4j日志 -->
    <setting name="logImpl" value="LOG4J"/>
</settings>

1.3.3 Habilitar caché L2

<settings>
    <!--开启二级缓存,默认是开启的,显示定义出来-->
    <setting name="cacheEnabled" value="true"/>
</settings>

1.4 etiqueta typeAliases

Para no especificar el nombre completo de la clase en todas partes, podemos definir un alias usando la etiqueta typeAliases. Dividido en dos formas:

  1. alias una clase
<typeAliases>
    <!--方式一,逐个设置,大小写不受影响-->
    <typeAlias type="com.hqyj.cl.pojo.User" alias="User"/>
    <typeAlias type="com.hqyj.cl.pojo.Person" alias="Person"/>
</typeAliases>
  1. Alias ​​del contenido de una carpeta
<typeAliases>
    <!--方式二,统一设置
    在没有注解@Alias()的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。
    比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值-->
    <package name="com.hqyj.cl.pojo"/>
</typeAliases>

1.5 etiqueta typeHandlers

typeHandlers convierte principalmente el valor adquirido en un tipo Java razonablemente. En typeHandler, se divide en jdbcType y javaType, entre los cuales jdbcType se usa para definir el tipo de base de datos, y javaType se usa para definir el tipo de Java, y el rol de typeHandler es realizar la conversión mutua entre jdbcType y javaType. No necesitamos configurarlo manualmente porque MyBatis tiene controladores de tipo predeterminados.

1.6 etiqueta de ambientes

​ En la pestaña de entornos, se pueden configurar múltiples conjuntos de entornos operativos de MyBatis para mapear SQL a múltiples bases de datos diferentes. Se debe especificar un entorno operativo predeterminado (especificado por defecto), por el momento, solo necesitamos configurar un conjunto de MySQL.

1.6.1 etiqueta del administrador de transacciones

​ MyBatis admite dos gestores de transacciones, a saber, JDBC y MANAGED. Elegimos JDBC.

1.6.2 etiqueta de fuente de datos

​ Se utiliza para configurar las propiedades de conexión de la base de datos, como el nombre del controlador, la URL, el nombre de usuario y la contraseña de la base de datos a la que conectarse, etc. Hay tres valores (UNPOOLED, POOLED, JNDI), elegimos POOLED

<!--数据库连接源-->
<dataSource type="POOLED">
    <!--获取配置驱动-->
    <property name="driver" value="${driver}"/>
    <!--获取配置url-->
    <property name="url" value="${url}"/>
    <!--获取配置账号-->
    <property name="username" value="${username!=null?username:root}"/>
    <!--获取配置密码-->
    <property name="password" value="${password}"/>
</dataSource>

Mapeo de 1.7resultMap (en el archivo Mapper.xml)

<!--定义结果集映射-->
<resultMap id="userMap" type="com.hqyj.pojo.User">
    <!--id主键 使用id标签-->
    <id column="id" property="id"></id>
    <result column="username" property="username"></result>
    <result column="password" property="password"></result>
</resultMap>

1.9 etiqueta de mapeadores

La etiqueta mappers se utiliza para especificar la ruta del archivo de mapeo SQL de MyBatis.

1.9.1 etiqueta del mapeador

mapper es una subetiqueta de mapeadores. El atributo de recurso en mapper se usa para especificar la ruta del archivo de mapeo SQL (ruta de recurso de clase). Hay muchas formas, tres de las cuales se usan aquí

<!--映射器,映射器的 XML 映射文件包含了 SQL 代码和映射定义信息-->
<mappers>
    <!--使用相对于类路径的资源引用,这是相对于类路径,UserMapper.xml存在resources下的mapper包中-->
    <mapper resource="mapper/UserMapper.xml"/>

    <!-- 使用映射器接口实现类的完全限定类名 mapper文件必须和接口在同一个包下,类名和mapper文件名必须相同-->
    <mapper class="com.hqyj.cl.mapper.UserMapper"/>

    <!-- 将包内的映射器接口实现全部注册为映射器 只需要指定到包名即可,mapper文件必须和接口在同一个包下,接口名和mapper文件名必须相同-->
    <package name="com.hqyj.cl.mapper"/>
</mappers>

Cinco, mapeador (mapeador)

​ El mapeador es el archivo más importante de MyBatis, que contiene un conjunto de sentencias SQL (como consultar, agregar, eliminar, modificar), que se denominan sentencias de mapeo o sentencias SQL de mapeo.

El mapeador consta de una interfaz Java y un archivo XML (o anotación), y sus funciones son las siguientes:

  • Definir tipo de parámetro
  • Configure el caché, el valor predeterminado es el caché de primer nivel
  • Proporcione una declaración SQL y SQL dinámico
  • Definir la relación de mapeo entre los resultados de la consulta y POJO

El mapeador tiene las siguientes dos implementaciones

  • Se realiza mediante un archivo XML, como el archivo XML que describimos en el archivo mybatis-config.xml, que se utiliza para generar el mapeador. forma recomendada.
  • Realizado por anotación, utilice el objeto de configuración para registrar la interfaz del asignador.

1. Mapeador de implementación XML

El mapeador de definiciones XML se divide en dos partes: interfaz y XML.

1.1 Definir la interfaz

public interface UserMapper {
    
    
    List<User> getUserList();
}

1.2 Definir UserMapper.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.hqyj.cl.mapper.UserMapper">
    <select id="getUserList" resultType="com.hqyj.cl.pojo.User">
        select * from `user`
    </select>
</mapper>

1.2.1 Descripción

  1. El espacio de nombres se utiliza para definir un espacio de nombres, que es coherente con el nombre completo de la interfaz definida.
  2. <select> El elemento indica que se trata de una instrucción de consulta y el atributo id se utiliza para identificar este SQL. resultType indica que lo que se devuelve es un valor de tipo Usuario.

1.3 Modificar archivo de configuración de MyBatis

Agrega el siguiente código al archivo de configuración de MyBatis

<!--该语句用来引入 XML 文件,MyBatis 会读取 UserMapper.xml 文件,生成映射器-->
<mapper resource="com/hqyj/cl/mapper/UserMapper.xml"/>

1.4 Código de prueba

@Test
public void getUserList() throws IOException {
    
    
    // 读取配置文件mybatis-config.xml
    InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
    // 根据配置文件构建SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
    // 通过SqlSessionFactory创建SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 通过SqlSession对象获取StudentMapper的代理对象
    StudentMapper mapper = sqlSession.getMapper(UserMapper.class);
    // 使用代理mapper对象查询全部的用户信息
    List<User> userList = mapper.getUserList();
    System.out.println(userList);
}

2. Mapeador de implementos de anotación

Para implementar el mapeador usando anotaciones, solo necesita usar anotaciones de Java en la interfaz e inyectar SQL

2.1 Código de prueba

public interface UserMapper {
    
    
    @Select(value = "select * from user")
    public List<User> getUserList();
}

2.1.1 Descripción

  1. Usamos la anotación @Select e inyectamos la misma declaración de selección que en el XML.
  2. Si se utilizan anotaciones y archivos XML para definir al mismo tiempo, el método XML anulará el método de anotación. (Use solo un método de configuración y es posible que se informen errores)
  3. Para declaraciones simples, puede usar anotaciones y para declaraciones complejas, se recomienda usar XML.

3. Principales elementos del mapeador MyBatis

Se explicará uno por uno en el estudio de seguimiento.

nombre del elemento describir Observación
mapeador El nodo raíz del archivo de mapeo, con solo un atributo llamado espacio de nombres La función del espacio de nombres es la siguiente: se utiliza para distinguir diferentes mapeadores y vincula de forma única globalmente la interfaz DAO, es decir, la programación orientada a la interfaz. Cuando un espacio de nombres está vinculado a una interfaz, no es necesario escribir la clase de implementación de la interfaz, MyBatis encontrará la configuración del mapeador correspondiente a través del nombre completo de la interfaz para ejecutar la instrucción SQL. Por lo tanto, el nombre del espacio de nombres debe ser el mismo que el nombre de la interfaz.
seleccionar Sentencia de consulta, uno de los elementos más utilizados y más complejos Puede personalizar parámetros, devolver conjuntos de resultados, etc.
insertar insertar declaración Devuelve un número entero después de la ejecución, que representa el número de elementos insertados
actualizar declaración de actualización Devuelve un número entero después de la ejecución, que representa el número de elementos actualizados
borrar eliminar declaración Devuelve un número entero después de la ejecución, que representa el número de elementos eliminados
mapa de parámetros Definir la relación de asignación de parámetros Elemento a eliminar, obsoleto
sql Permite definir una parte de SQL y luego referirse a ella en todas partes Por ejemplo, un nombre de columna de tabla, podemos definirlo una vez y usarlo en múltiples declaraciones SQL
resultadoMapa Utilizado para describir la correspondencia entre los conjuntos de resultados de la base de datos y los objetos, es el elemento más complejo y poderoso. Proporcionar reglas de mapeo
cache Configurar el caché para un espacio de nombres dado -
caché-ref Referencias a otras configuraciones de caché de espacio de nombres -

Seis, MyBatis ejecuta SQL de dos formas

MyBatis tiene dos formas de ejecutar sentencias SQL, de la siguiente manera:

  1. Enviar SQL a través de SqlSession
  2. Obtenga la interfaz de Mapper a través de SqlSession y envíe SQL a través de la interfaz de Mapper

1, sesión SQL

Después de que haya un mapeador, puede enviar SQL a través de SqlSession Hay dos métodos de consulta comunes en MyBatis, a saber, selectOne y selectList.

1.1 seleccione uno

El método selectOne indica que se utiliza la consulta y solo se devuelve un objeto, y se debe especificar la condición de la consulta. Solo se puede consultar 0 o 1 registro, y si hay más de 1 registro, se producirá el error de operación. Los formatos comunes son los siguientes (existen otros métodos de sobrecarga, elija según sus necesidades)

sqlSession.selectOne(String arg0, Object arg1)

1.2 lista de selección

El método selectList representa una consulta y devuelve una lista. Se pueden consultar 0 o N registros. Los formatos comunes son los siguientes

sqlSession.selectList(String arg0, Object arg1)

1.3 Descripción

  1. En el formato de sintaxis anterior, el objeto String se compone de un espacio de nombres y un id de SQL, que localiza completamente un SQL, de modo que MyBatis encontrará el SQL correspondiente. El objeto Object es el parámetro que debe pasarse, es decir, la condición de consulta
  2. El selectList implementado por selectOne se puede implementar, es decir, solo hay un objeto en la lista. Pero lo que selectList puede lograr, es posible que selectOne no pueda lograrlo
  3. Si solo hay un SQL cuyo id es getUserList en MyBatis, entonces se puede eliminar el nombre de la ruta del paquete

2. Interfaz del mapeador

SqlSession también puede obtener la interfaz de Mapper y enviar SQL a través de la interfaz de Mapper, como se muestra a continuación.

UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();

2.1 Descripción

  1. Obtenga una interfaz Mapper a través del método getMapper de SqlSession y luego llame a sus métodos. Debido a que el SQL definido por el archivo XML o la anotación de la interfaz se puede buscar por "nombre completo de la clase + nombre del método", MyBatis habilitará el SQL correspondiente para ejecutarse y devolver el resultado.

Siete, etiqueta CRUD

Solo la etiqueta de selección tiene el atributo resultType, porque solo la operación de consulta necesita especificar el tipo de resultado devuelto en consecuencia.

1. seleccionar etiqueta

En MyBatis, la etiqueta de selección es la etiqueta de lenguaje SQL más utilizada y potente para realizar operaciones de consulta. El formato es el siguiente

<select id="queryUserByUsername" resultType="user" parameterType="string">
    select * from `user` where `username` like concat ('%',#{username},'%')
</select>

1.1 Descripción

  1. Los parámetros se pueden definir al ejecutar sentencias SQL, y los parámetros pueden ser un tipo de parámetro simple, como int, float, String; o un tipo de parámetro complejo, como JavaBean, Map, etc. MyBatis proporciona poderosas reglas de mapeo Después de ejecutar SQL, MyBatis mapeará automáticamente el conjunto de resultados a JavaBean.
  2. Para hacer coincidir automáticamente los resultados de la consulta de la base de datos con los atributos en el tipo de valor de retorno, se suele utilizar el mismo conjunto de reglas de nomenclatura para la base de datos MySQL y JavaBean, es decir, la regla de joroba de nomenclatura de Java, de modo que no se requiere ninguna asignación. requerido (nombres y atributos de los campos de la tabla de la base de datos) Se requiere la asignación manual cuando los nombres son inconsistentes)
  3. El paso y uso de parámetros #{参数名}es equivalente a decirle a MyBatis que genere parámetros PreparedStatement.

1.2 Propiedades comunes

Nombre del Atributo describir Observación
identificación Se usa en combinación con el espacio de nombres de Mapper y es un identificador único para que MyBatis llame Si el espacio de nombres + id no es único, MyBatis lanza una excepción
tipo de parámetro Indica el nombre totalmente calificado o el alias del tipo de parámetro entrante de la instrucción SQL entrante. Es un atributo opcional, y MyBatis puede inferir los parámetros de la declaración entrante específica Admite tipos de datos básicos y tipos de datos complejos como JavaBean y Map
tipo de resultado El tipo (nombre completo o alias) devuelto después de ejecutar la sentencia SQL. Si es un tipo de colección, se devuelve el tipo del elemento de la colección y se puede usar uno de resultType o resultMap al devolver -
resultadoMapa Es una referencia a un conjunto de mapeo, <resultMap>se usa con el elemento y se puede devolver con uno de resultType o resultMap Es el elemento más complejo de MyBatis, que puede configurar reglas de mapeo, cascada, typeHandler, etc.
vaciar caché Se usa para establecer si se requiere que MyBatis borre la caché local y la caché de segundo nivel de la consulta anterior después de llamar a la instrucción SQL El valor predeterminado es falso. Si se establece en verdadero, la memoria caché local y la memoria caché de segundo nivel se borrarán cada vez que se invoque la instrucción SQL.
usarcaché Habilite el cambio del caché de segundo nivel, el valor predeterminado es verdadero, lo que significa que los resultados de la consulta se almacenan en el caché de segundo nivel -
se acabó el tiempo Se utiliza para establecer el parámetro de tiempo de espera, la unidad es segundos (s) y se lanzará una excepción cuando expire el tiempo de espera -
fetchSize Obtener el número total de registros establecidos El valor predeterminado es el número establecido por el controlador JDBC proporcionado por el fabricante de la base de datos.
tipo de declaración Dile a MyBatis con qué Sentencia JDBC trabajar, el valor es STATEMENT (Declaración), PREPARADO (PreparedStatement), CALLABLE (CallableStatement) -
resultSetType Esto es para la interfaz ResultSet de JDBC, y su valor se puede establecer en FORWARD_ONLY (solo permite el acceso directo), SCROLL_SENSITIVE (desplazamiento bidireccional, pero no actualizado a tiempo), SCROLLJNSENSITIVE (desplazamiento bidireccional, actualización oportuna) -

1.3 Múltiples parámetros

A veces, necesitamos pasar varios parámetros para ejecutar declaraciones SQL, como el inicio de sesión del usuario; en este momento, hay tres formas de lograrlo, a saber, usar Map para pasar parámetros, usar anotaciones para pasar parámetros y usar JavaBean para pasar parámetros. , teniendo en cuenta el rendimiento, etc. Pregunta, no se recomienda usar Map para pasar parámetros, por lo que ahora analizamos los dos últimos casos

1.3.1 Uso de anotaciones para pasar parámetros

Use la anotación @Param() de MyBatis para pasar parámetros, como se muestra a continuación

1.3.1.2 Caso
  1. interfaz
//用户登录
User login(@Param("username")String username,@Param("password")String password);
  1. Mapeador
<!--用户登录-->
<select id="login" resultType="User">
    select * from user where username = #{username} and password = #{password}
</select>
1.3.1.2 Descripción

​ Cuando pasemos el parámetro a segundo plano, MyBatis sabrá que #{name} representa el parámetro name a través del nombre proporcionado por @Param, lo que mejora la legibilidad del parámetro. Pero si este SQL tiene una consulta con 10 parámetros, reducirá la legibilidad y aumentará la complejidad del código.

1.3.2 Usando JavaBean para pasar parámetros

En el caso de demasiados parámetros, MyBatis permite organizar un JavaBean y establecer parámetros a través de métodos simples de setter y getter para mejorar la legibilidad. Como sigue

1.3.2.1 Caso
  1. interfaz
//增加用户
int selectUser(User user);
  1. Mapeador
<!--增加用户-->
<select id="selectUser" resultType="User">
    select * from user where username = #{username} and password = #{password} and position = #{position}
</select>

1.3.3 Diferencias

La diferencia entre los dos métodos anteriores es la siguiente.

  • Pasar parámetros usando la anotación @Param se verá afectado por la cantidad de parámetros. Cuando n≤5, es la mejor manera de pasar parámetros, porque es más intuitivo, cuando n>5, múltiples parámetros traerán dificultades a la llamada.
  • Cuando el número de parámetros es superior a 5, se recomienda utilizar el método JavaBean.

2. insertar etiqueta

La etiqueta de inserción de MyBatis se utiliza para definir la declaración de inserción y ejecutar la operación de inserción. Cuando MyBatis ejecuta una declaración de inserción, devuelve el número de filas que afecta a la base de datos.

2.1 Caso

Agregue la función de usuario a través de la etiqueta de inserción

  1. interfaz
//增加用户
int addUser(User user);
  1. Mapeador
<!--增加用户-->
<insert id="addUser">
    insert into user values (null,#{username},#{password},#{userPhone},#{createTime},#{position})
</insert>

clase de prueba

sqlSession.commit(); requiere compromiso

2.2 Atributos comunes

Nombre del Atributo describir Observación
identificación Se usa en combinación con el espacio de nombres de Mapper y es un identificador único para que MyBatis llame MyBatis lanza una excepción si el espacio de nombres + id no es único
tipo de parámetro El nombre completo o alias del tipo de parámetro que se pasa a la instrucción SQL, que es un atributo opcional. Admite tipos de datos básicos y tipos de datos complejos como JavaBean y Map
propiedad clave La función de este atributo es asignar el valor de retorno de la operación de inserción a un atributo de la clase PO, normalmente el atributo correspondiente a la clave primaria. Si se trata de una clave principal conjunta, los valores múltiples se pueden separar con comas. -
useGeneratedKe 该属性用来设置,是否使用 JDBC 提供的 getGenereatedKeys() 方法,获取数据库内部产生的主键并赋值到 keyProperty 属性设置的请求对象的属性中,例如 MySQL、SQL Server 等自动递增的字段,其默认值为 false。 该属性值设置为 true 后,会将数据库生成的主键回填到请求对象中,以供其他业务使用。
flushCache 该属性用于设置执行该操作后,是否会清空二级缓存和本地缓存,默认值为 true。 -
timeout 该属性用于设置执行该操作的最大时限,如果超时,就抛异常。 -
databaseId 取值范围 oracle、mysql 等,表示数据库厂家;元素内部可通过 <if test="_databaseId = 'oracle'"> 来为特定数据库指定不同的 sql 语句。 MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。
keyColumn 该属性用于设置第几列是主键,当主键列不是表中的第 1 列时,就需要设置该属性。如果是联合主键,可以将多个值用逗号隔开。 -

2.3 多参数

和select标签规则一样

3、update标签

MyBatis update 标签用于定义更新语句,执行更新操作。当 MyBatis 执行完一条更新语句后,会返回一个整数,表示受影响的数据库记录的行数。

3.1 案例

  1. 接口
//通过用户姓名修改用户
int updateUserByUserName(User user);
  1. Mapper
<!--通过用户姓名修改用户-->
<update id="updateUserByUsername">
    update user set phone = #{phone},password = #{password} where username = #{username}
</update>

3.2 常用属性

属性名称 描述 备注
id 它和 Mapper 的命名空间组合起来使用,是唯一标识符,供 MyBatis 调用 如果命名空间+ id 不唯一,那么 MyBatis 抛出异常
parameterType 传入 SQL 语句的参数类型的全限定名或别名,它是一个可选属性。 支持基本数据类型和 JavaBean、Map 等复杂数据类型
flushCache 该属性用于设置执行该操作后,是否会清空二级缓存和本地缓存,默认值为 true。 -
timeout 该属性用于设置 SQL 执行的超时时间,如果超时,就抛异常。 -
statementType 执行 SQL 时使用的 statement 类型, 默认为 PREPARED,可选值:STATEMENT,PREPARED 和 CALLABLE。 -

3.3 多参数

和select标签规则一样

4、delete标签

MyBatis delete 标签用于定义 delete 语句,执行删除操作。当 MyBatis 执行完一条更新语句后,会返回一个整数,表示受影响的数据库记录的行数。

4.1 案例

  1. 接口
//删除某个用户
int delUserById(int id);
  1. Mapper
<!--删除某个用户-->
<delete id="delUserById">
    delete from user where id = #{id}
</delete>

4.2 常用属性

属性名称 描述 备注
id 它和 Mapper 的命名空间组合起来使用,是唯一标识符,供 MyBatis 调用 如果命名空间+ id 不唯一,那么 MyBatis 抛出异常
parameterType 传入 SQL 语句的参数类型的全限定名或别名,它是一个可选属性。 支持基本数据类型和 JavaBean、Map 等复杂数据类型
flushCache 该属性用于设置执行该操作后,是否会清空二级缓存和本地缓存,默认值为 true。 -
timeout 该属性用于设置 SQL 执行的超时时间,如果超时,就抛异常。 -
statementType 执行 SQL 时使用的 statement 类型, 默认为 PREPARED,可选值:STATEMENT,PREPARED 和 CALLABLE。 -

4.3 多参数

和select标签规则一样

八、resultMap

​ resultMap 是 MyBatis 中最复杂的元素,主要用于解决实体类属性名与数据库表中字段名不一致的情况,可以将查询结果映射成实体对象。现有的 MyBatis 版本只支持 resultMap 查询,我们通过案例分析

1、构成

<resultMap id="" type="">
<constructor><!-- 类再实例化时用来注入结果到构造方法 -->
    <idArg/><!-- ID参数,结果为ID -->
    <arg/><!-- 注入到构造方法的一个普通结果 -->
</constructor>
<id/><!-- 用于表示哪个列是主键 -->
<result/><!-- 注入到字段或JavaBean属性的普通结果 -->
<association property=""/><!-- 用于一对一关联 -->
<collection property=""/><!-- 用于一对多、多对多关联 -->
<discriminator javaType=""><!-- 使用结果值来决定使用哪个结果映射 -->
    <case value=""/><!-- 基于某些值的结果映射 -->
</discriminator>
</resultMap>

1.1 说明

  • <resultMap>元素的 type 属性表示需要的 POJO,id 属性是 resultMap 的唯一标识
  • 子元素 <constructor> 用于配置构造方法。当一个 POJO 没有无参数构造方法时使用。一般不用
  • 子元素 <id> 用于表示哪个列是主键。允许多个主键,多个主键称为联合主键。
  • 子元素<result> 用于表示 POJO 和 SQL 列名的映射关系。
  • 子元素 <association><collection><discriminator> 用在级联的情况下。后续学习

id 和 result 元素都有以下属性

元素 说明
property 映射到列结果的字段或属性。如果 POJO 的属性和 SQL 列名(column元素)是相同的,那么 MyBatis 就会映射到 POJO 上
column 对应 SQL 列
javaType 配置 Java 类型。可以是特定的类完全限定名或 MyBatis 上下文的别名
jdbcType 配置数据库类型。这是 JDBC 类型,MyBatis 已经为我们做了限定,基本支持所有常用数据库类型
typeHandler 类型处理器。允许你用特定的处理器来覆盖 MyBatis 默认的处理器。需要指定 jdbcType 和 javaType 相互转化的规则

1.2 获取结果集的两种方式

1.2.1 使用Map存储结果集

不推荐使用该方式

  1. 接口
// 用户列表
List<Map<String,Object>> queryAllUser();
  1. Mapper
<select id="selectAllUser" resultType="map">
    select * from `user`
</select>

**注意事项:**Map 的 key 是 select 语句查询的字段名(必须完全一样),而 Map 的 value 是查询返回结果中字段对应的值,一条记录映射到一个 Map 对象中。

1.2.2 使用POJO存储结果集

推荐使用该方式

  1. POJO类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    
    
    private int id;
    private String username;
    private String password;
}
  1. 接口
public interface UserMapper {
    
    
    List<User> getUserList();
}
  1. Mapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hqyj.cl.dao.UserDao">
    <resultMap id="userMap" type="User">
        <id column="id" property="id"/>
        <result column="username" property="userName"/>
        <result column="password" property="password"/>
    </resultMap>
	<!--查询用户列表-->
    <select id="getUserList" resultMap="userMap">
        select * from `user`
    </select>
</mapper>
1.2.2.1 说明
  1. resultMap 元素的属性 id 代表这个 resultMap 的标识,type 标识需要映射的 POJO。我们可以使用 MyBatis 定义好的类的别名或自定义类的全限定名。
  2. 使用 property 元素指定 User的属性名称 username,column 表示数据库中 user表的 SQL 列名 username,将 POJO 和 SQL 的查询结果一 一对应。
  3. MyBatis 的每一个查询映射的返回类型都是 resultMap,只是当我们提供的返回类型是 resultType 时,MyBatis 会自动把对应的值赋给 resultType 所指定对象的属性,而当我们提供的返回类型是 resultMap 时,MyBatis 会将数据库中的列数据复制到对象的相应属性上,可用于复制查询。
  4. resultMap 和 resultType 不能同时使用。

九、注解

为了简化 XML 的配置,MyBatis 提供了注解,这些注解主要分为三大类,即 SQL 语句映射、结果集映射和关系映射。我们就逐一学习

1、SQL 语句映射

1.1 @Insert

实现新增功能

@Insert("insert into user(name,sex,age) values(#{name},#{sex},#{age})")
int addUser(User user);

1.2 @SelectKey

插入后,获取id的值

@Insert("insert into user(id,name) values(#{id},#{name})")
@SelectKey(statement = "select last_insert_id()", keyProperty = "id", keyColumn = "id", resultType = int.class,before = false)
int insert(User user);

@SelectKey 各个属性含义如下

  • statement:表示要运行的 SQL 语句;
  • keyProperty:可选项,表示将查询结果赋值给代码中的哪个对象;
  • keyColumn:可选项,表示将查询结果赋值给数据表中的哪一列;
  • resultType:指定 SQL 语句的返回值;
  • before:默认值为 true,在执行插入语句之前,执行 select last_insert_id()。值为 flase,则在执行插入语句之后,执行 select last_insert_id()。

1.3 @Select

实现查询功能

增加templateMapper.xml文件在mapper包中 namespace属性空着

mybatis-config.xml中要扫描包

@Select("Select * from user")
@Results({
    
    
    @Result(id = true, column = "id", property = "id"),
    @Result(column = "name", property = "name"),
    @Result(column = "sex", property = "sex"),
    @Result(column = "age", property = "age")
})
List<User> queryAllUser();

@Results配置映射关系,如果mybatis-config.xml中关闭了驼峰命名,数据库字段与pojo类成员变量不能自动映射可以使用该注解

1.4 @Update

实现更新功能

@Update("update user set name= #{name},sex = #{sex},age =#{age} where id = #{id}")
void updateUserById(User user);

1.5 @Delete

实现删除功能

@Delete("delete from  user  where id =#{id}")
void deleteById(Integer id);

1.6 @Param

用于在 Mapper 接口中映射多个参数,之前已经说明并演示

2、结果集映射

@Result、@Results、@ResultMap 是结果集映射的三大注解。

2.1 案例

@Select({
    
    "select id, name, class_id from student"})
@Results(id="studentMap", value={
    
    
    @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
    @Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
    @Result(column="class_id ", property="classId", jdbcType=JdbcType.INTEGER)
})
List<Student> selectAllStudent();

@Results 各个属性的含义

  • id:表示当前结果集声明的唯一标识,可以通过id重复利用;
  • value:表示结果集映射关系;
  • @Result:代表一个字段的映射关系。其中,column 指定数据库字段的名称,property 指定实体类属性的名称,jdbcType 数据库字段类型,id 为 true 表示主键,默认 false。

使用 @ResultMap 来引用映射结果集,其中 value 可省略

@Select({
    
    "select id, name, class_id from student where id = #{id}"})
@ResultMap(value="studentMap")
Student selectById(int id);

3、关系映射

基础学生类增加成员变量修改数据类型,记得要重构有参构造方法。

3.1 @one

用于一对一关系映射

@Select("select * from stu")
@Results({
    
    
    @Result(id=true,property="id",column="id"),
    @Result(property="student_name",column="name"),
   @Result(property="addr",column="fk_addr_id",one=@One(select="com.hqyj.cl.mapper.StudentMapper.getAddr"))
})
List<Student> getAllStudents();

@Select("select * from addr where id = #{id}")
@Results({
    
    
    @Result(id=true,property="id",column="id"),
    @Result(property="addrName",column="addr_name")
})
Addr getAddr(int id);

3.2 @many

用于一对多关系映射

@Select("select * from stu")
@Results({
    
    
    @Result(id=true,property="id",column="id"),
    @Result(property="student_name",column="name"),
  @Result(property="teacher",column="fk_teacher_id",many=@Many(select="com.hqyj.cl.mapper.StudentMapper.getTeacher"))
})
List<Student> getAllStudents();

@Select("select * from teacher where id = #{id}")
@Results({
    
    
    @Result(id=true,property="id",column="id"),
    @Result(property="teacherName",column="teacher_name")
})
List<Teacher> getTeacher(int id);

3.3 多对多

在一对多的基础上,增加一个外表student_teacher,实现对student表和teacher表的关联

@Select("select * from stu")
@Results({
    
    
    @Result(id=true,property="id",column="id"),
    @Result(property="student_name",column="name"),    @Result(property="teacher",column="fk_teacher_id",many=@Many(select="com.hqyj.cl.mapper.StudentMapper.getTeacher"))
})
List<Student> getAllStudents();

@Select("select * from teacher t,student_fk_teacher st where t.id = st.teacher_id and st.student_id = #{id}")
@Results({
    
    
    @Result(id=true,property="id",column="id"),
    @Result(property="teacherName",column="teacher_name"),
})
List<Teacher> getTeacher(int id);

十、MyBatis关联(级联)查询

级联关系是一个数据库实体的概念,有 3 种级联关系,分别是一对一级联、一对多级联以及多对多级联。比如一个人对应一张身份证,一张身份证对应一个人、一个班级拥有多个学生,一个学生只能够属于某个班级、 一个学生可以选修多门课程,一个课程可以被多个学生选修。

1、一对一

在 MyBatis 中,通过 <resultMap> 元素的子元素 <association> 处理一对一级联关系。示例代码如下

POJO类和数据库设计,Student、Teacher、Addr三个类

  1. Student类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    
    
    private int id;
    private String studentName;
    private Addr addr;
    private List<Teacher> teacher;
}
  1. Addr类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Addr {
    
    
    private int id;
    private String addr;
}
  1. 接口
List<Student> selectAllStudent();
  1. Mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hqyj.cl.mapper.StudentMapper">
    <resultMap id="studentMap" type="Student">
        <id property="id" column="id"/>
        <result property="studentName" column="student_name"/>
        <association property="addr">
            <id property="id" column="id"/>
            <result property="addr" column="addr"/>
        </association>
    </resultMap>

    <select id="selectAllStudent" resultMap="studentMap">
        select * from `stu` s,`addr` a where s.fk_addr_id = a.id 
    </select>

</mapper>
  1. 测试
@Test
public void getAllUser() throws IOException {
    
    
    // 读取配置文件mybatis-config.xml
    InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
    // 根据配置文件构建SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
    // 通过SqlSessionFactory创建SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    List<Student> studentList = mapper.selectAllStudent();
    // SqlSession执行文件中定义的SQL,并返回映射结果
    System.out.println(studentList);
}

<association> 元素中通常使用以下属性。

  • property:指定映射到实体类的对象属性。
  • column:指定表中对应的字段(即查询返回的列名)。
  • javaType:指定映射到实体对象属性的类型。
  • select:指定引入嵌套查询的子 SQL 语句,该属性用于关联映射中的嵌套查询。

2、一对多

在 MyBatis 中,通过 <resultMap> 元素的子元素 <collection> 处理一对多级联关系,collection 可以将关联查询的多条记录映射到一个 list 集合属性中。示例代码如下

  1. Teacher类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    
    
    private int id;
    private String teacherName;
}
  1. 接口
List<Student> selectAllStudent();
  1. Mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hqyj.cl.mapper.StudentMapper">
    <resultMap id="studentMap" type="Student">
        <id property="id" column="id"/>
        <result property="studentName" column="student_name"/>
        <collection property="teacher" ofType="teacher">
            <id property="id" column="id"/>
            <result property="teacherName" column="teacher_name"/>
        </collection>
    </resultMap>

    <select id="selectAllStudent" resultMap="studentMap">
        select * from `stu` s,`addr` a,`teacher` t where s.fk_teacher_id = t.id
    </select>

</mapper>
  1. 测试
@Test
public void getAllUser() throws IOException {
    
    
    // 读取配置文件mybatis-config.xml
    InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
    // 根据配置文件构建SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
    // 通过SqlSessionFactory创建SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    List<Student> studentList = mapper.selectAllStudent();
    // SqlSession执行文件中定义的SQL,并返回映射结果
    System.out.println(studentList);
}

<collection> 元素中通常使用以下属性。

  • property:指定映射到实体类的对象属性。
  • column:指定表中对应的字段(即查询返回的列名)。
  • javaType:指定映射到实体对象属性的类型。
  • select:指定引入嵌套查询的子 SQL 语句,该属性用于关联映射中的嵌套查询。

3、多对多

​ 实际应用中,由于多对多的关系比较复杂,会增加理解和关联的复杂度,所以应用较少。MyBatis 没有实现多对多级联,推荐通过两个一对多级联替换多对多级联,以降低关系的复杂度,简化程序。

十一、MyBatis动态SQL

​ 动态 SQL 是 MyBatis 的强大特性之一。在 JDBC 或其它类似的框架中,开发人员通常需要手动拼接 SQL 语句。根据不同的条件拼接 SQL 语句是一件极其痛苦的工作。动态 SQL 大大减少了编写代码的工作量,更体现了 MyBatis 的灵活性、高度可配置性和可维护性。MyBatis 也可以在注解中配置 SQL,但是由于注解功能受限,且对于复杂的 SQL 语句来说可读性差,所以使用较少。

1、动态SQL元素

MyBatis 的动态 SQL 包括以下几种元素

元素 作用 备注
if 判断语句 单条件分支判断
choose(when、otherwise) 相当于 Java 中的 switch case 语句 多条件分支判断
trim、where 辅助元素 用于处理一些SQL拼装问题
foreach 循环语句 在in语句等列举条件常用
bind 辅助元素 拼接参数

1.1 if标签

MyBatis if 类似于 Java 中的 if 语句,是 MyBatis 中最常用的判断语句。

1.1.1 格式

<if test="判断条件">
    <!--条件为true时执行SQL语句-->
    SQL语句
</if>

1.1.2 案例

  1. 接口
List<User> selectAllUser(User user);
  1. Mapper
<select id="selectAllUser" resultMap="userMap">
    select * from user where 1=1
    <if test="name != null">
        and `name` like #{name}
    </if>
    <if test="state != 0">
        and state like #{state}
    </if>
</select>
  1. 测试
@Test
public void selectAllUser() throws IOException {
    
    
    // 读取配置文件mybatis-config.xml
    InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
    // 根据配置文件构建SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
    // 通过SqlSessionFactory创建SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = new User();
    user.setName("王五");
    List<User> userList = mapper.selectAllUser(user);
    // SqlSession执行文件中定义的SQL,并返回映射结果
    System.out.println(userList);
}

1.2 choose、when和otherwise标签

​ MyBatis 中动态语句 choose-when-otherwise 类似于 Java 中的 switch-case-default 语句。由于 MyBatis 并没有为 if 提供对应的 else 标签,如果想要达到<if><else></else> </if> 的效果,可以借助 <choose><when><otherwise> 来实现。

1.2.1 格式

​ choose 标签按顺序判断其内部 when 标签中的判断条件是否成立,如果有一个成立,则执行相应的 SQL 语句,choose 执行结束;如果都不成立,执行 otherwise 中的 SQL 语句。这类似于 Java 的 switch 语句,choose为switch,when 为 case,otherwise则为default。

<choose>
    <when test="判断条件1">
        SQL语句1
    </when >
    <when test="判断条件2">
        SQL语句2
    </when >
    <when test="判断条件3">
        SQL语句3
    </when >
    <otherwise>
        SQL语句4
    </otherwise>
</choose>

1.2.1 案例

  1. 接口
List<User> selectAllUser(User user);
  1. Mapper
<select id="selectAllUser" resultMap="userMap">
    select * from user where 1=1
    <choose>
        <when test="name != null and name !=''">
            AND name LIKE CONCAT('%',#{name},'%')
        </when>
        <when test="state != 0 and state == 1">
            AND state = #{state}
        </when>
        <otherwise>
            AND password is not null
        </otherwise>
    </choose>
</select>
  1. 测试
@Test
public void selectAllUser() throws IOException {
    
    
    // 读取配置文件mybatis-config.xml
    InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
    // 根据配置文件构建SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
    // 通过SqlSessionFactory创建SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = new User();
    List<User> userList = mapper.selectAllUser(user);
    // SqlSession执行文件中定义的SQL,并返回映射结果
    System.out.println(userList);
}

1.3 where标签

​ 在上述标签SQL代码的编写中,我们不难发现,每一条SQL 语句中加入了一个条件“1=1”,如果没有加入这个条件,那么可能就会变成下面这样一条错误的语句。

SELECT * FROM user AND name LIKE CONCAT('%',#{name},'%')

显然以上语句会出现 SQL 语法异常,但加入“1=1”这样的条件又非常奇怪,所以 MyBatis 提供了 where 标签

1.3.1 格式

where 标签主要用来简化 SQL 语句中的条件判断,可以自动处理 AND/OR 条件,语法如下

<where>
    <if test="判断条件">
        AND/OR ...
    </if>
</where>

**注意事项:if 语句中判断条件为 true 时,where 关键字才会加入到组装的 SQL 里面,否则就不加入。where 会检索语句,它会将 where 后的第一个 SQL 条件语句**的 AND 或者 OR 关键词去掉。

1.3.2 案例

  1. 接口
List<User> selectAllUser(User user);
  1. Mapper
<select id="selectAllUser" resultMap="userMap">
    select * from user
    <where>
        <if test="name != null">
            name like #{name}
        </if>
        <if test="state != 0">
            AND state like #{state}
        </if>
    </where>
</select>
  1. 测试
@Test
public void selectAllUser() throws IOException {
    
    
    // 读取配置文件mybatis-config.xml
    InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
    // 根据配置文件构建SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
    // 通过SqlSessionFactory创建SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = new User();
	user.setName("admin");
    List<User> userList = mapper.selectAllUser(user);
    // SqlSession执行文件中定义的SQL,并返回映射结果
    System.out.println(userList);
}

1.4 set标签

​ 在 Mybatis 中,update 语句可以使用 set 标签动态更新列。set 标签可以为 SQL 语句动态的添加 set 关键字,剔除追加到条件末尾多余的逗号

1.4.1 案例

  1. 接口
int updateUser(User user);
  1. Mapper
<update id="updateUser">
    UPDATE user
    <set>
        <if test="password!=null">
            password=#{password}
        </if>
        <if test="state==0 || state==1">
            state=#{state}
        </if>
    </set>
    WHERE name=#{name}
</update>
  1. 测试
@Test
public void updateUser() throws IOException {
    
    
    // 读取配置文件mybatis-config.xml
    InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
    // 根据配置文件构建SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
    // 通过SqlSessionFactory创建SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = new User();
    user.setName("admin");
    user.setState(1);
    int result = mapper.updateUser(user);
    // SqlSession执行文件中定义的SQL,并返回映射结果
    System.out.println(result);
}

**注意事项:**if判断中必须成立一个,并且where后面的条件对应的值必须传递,否则报错

1.5 foreach标签

​ 对于一些 SQL 语句中含有 in 条件,需要迭代条件集合来生成的情况,可以使用 foreach 来实现 SQL 条件的迭代。 Mybatis foreach 标签用于循环语句,它很好的支持了数据和 List、set 接口的集合,并对此提供遍历的功能。语法格式如下

<foreach item="item" index="index" collection="list|array|map key" open="(" separator="," close=")">
    参数值
</foreach>

foreach 标签主要有以下属性,说明如下。

  • item:表示本次迭代获取的元素,若collection为List、Set或者数组,则表示其中的元素;若collection为map,则代表key-value的value,该参数为必选
  • index:在list、Set和数组中,index表示当前迭代的位置,在map中,index代指是元素的key,该参数是可选项。
  • open:表示该语句以什么开始(既然是 in 条件语句,所以必然以(开始)。
  • separator:表示在每次进行迭代之间以什么符号作为分隔符(既然是 in 条件语句,所以必然以,作为分隔符)。
  • close:表示该语句以什么结束(既然是 in 条件语句,所以必然以)开始)。
  • collection表示迭代集合的名称,可以使用@Param注解指定,有以下四种情况
    • 如果传入的是单参数且参数类型是一个 List,collection 属性值为 list;
    • 如果传入的是单参数且参数类型是一个 array 数组,collection 的属性值为 array;
    • 如果如果传入的是单参数且参数类型是一个Set集合的时候,可以通过注解@Param("set")指定key值;
    • 如果传入的参数是多个,需要把它们封装成一个 Map,当然单参数也可以封装成 Map。Map 的 key 是参数名,collection 属性值是传入的 List 或 array 对象在自己封装的 Map 中的 key。必须加上注解@Param指定

1.5.1 案例

  1. 接口
List<User> selectUser(List<Integer> ageList);
  1. Mapper
<select id="selectUser" resultMap="userMap">
    SELECT * FROM user WHERE age in
    <foreach item="age" index="index" collection="list" open="("
             separator="," close=")">
        #{age}
    </foreach>
</select>
  1. 测试
@Test
public void selectUser() throws IOException {
    
    
    // 读取配置文件mybatis-config.xml
    InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
    // 根据配置文件构建SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
    // 通过SqlSessionFactory创建SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<Integer> ageList = new ArrayList<>();
    ageList.add(1);
    ageList.add(12);
    ageList.add(13);
    List<User> result = mapper.selectUser(ageList);
    // SqlSession执行文件中定义的SQL,并返回映射结果
    System.out.println(result);
}

1.6 bind标签

​ 每个数据库的拼接函数或连接符号都不同,例如 MySQL 的 concat 函数。这样 SQL 映射文件就需要根据不同的数据库提供不同的实现,显然比较麻烦,且不利于代码的移植。幸运的是,MyBatis 提供了 bind 标签来解决这一问题。

MyBatis bind 标签可以通过 OGNL(对象导航图语言) 表达式自定义一个上下文变量。

bind 元素属性如下

  • value:对应传入实体类的某个字段,可以进行字符串拼接等特殊处理。
  • name:给对应参数取的别名。

1.6.1 案例

  1. 接口
List<User> queryUser(String name);
  1. Mapper
<select id="queryUser" resultMap="userMap">
    <bind name="pattern" value="'%'+_parameter+'%'" />
    SELECT * FROM `user`
    WHERE name like #{pattern} 
</select>
  1. 测试
@Test
public void queryUser() throws IOException {
    
    
    // 读取配置文件mybatis-config.xml
    InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
    // 根据配置文件构建SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
    // 通过SqlSessionFactory创建SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = mapper.queryUser("a");
    // SqlSession执行文件中定义的SQL,并返回映射结果
    System.out.println(userList);
}

**注意事项:**以上代码中的“_parameter”代表传递进来的参数,它和通配符连接后,赋给了 pattern,然后就可以在 select 语句中使用这个变量进行模糊查询,提高了可移植性。

1.7 trim标签

​ 在 MyBatis 中除了使用 if+where 实现多条件查询,还有一个更为灵活的元素 trim 能够替代之前的做法。trim 一般用于去除 SQL 语句中多余的 AND 关键字、逗号或者给 SQL 语句前拼接 where、set 等后缀,可用于选择性插入、更新、删除或者条件查询等操作。

1.7.1 格式

<trim prefix="前缀" suffix="后缀" prefixOverrides="忽略前缀字符" suffixOverrides="忽略后缀字符">
    SQL语句
</trim>
1.7.1.1 属性说明
属性 描述
prefix 给SQL语句拼接的前缀,为 trim 包含的内容加上前缀
suffix 给SQL语句拼接的后缀,为 trim 包含的内容加上后缀
prefixOverrides 去除 SQL 语句前面的关键字或字符,该关键字或者字符由 prefixOverrides 属性指定。
suffixOverrides 去除 SQL 语句后面的关键字或者字符,该关键字或者字符由 suffixOverrides 属性指定

1.7.2 案例

  1. 接口
List<User> selectAllUser(User user);
  1. Mapper
<select id="selectAllUser" resultMap="userMap">
    select * from user
    <trim prefix="where" prefixOverrides="and">
        <if test="name != null">
            and `name` like #{name}
        </if>
        <if test="state != 0">
            and state like #{state}
        </if>
    </trim>
</select>
  1. 测试
@Test
public void selectAllUser() throws IOException {
    
    
    // 读取配置文件mybatis-config.xml
    InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
    // 根据配置文件构建SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
    // 通过SqlSessionFactory创建SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = new User();
    List<User> userList = mapper.selectAllUser(user);
    // SqlSession执行文件中定义的SQL,并返回映射结果
    System.out.println(userList);
}

十二、MyBatis分页功能

MyBatis 的分页功能是基于内存的分页,即先查询出所有记录,再按起始位置和页面容量取出结果。

1、pageHelper插件

在使用MyBatis分页功能时,通常和pageHelper插件配合使用

1.1 参数

PageInfo{
    
    
pageNum=1, 	//页数
pageSize=2, 	//页大小
size=2, 大小
startRow=1, 	//开始行
endRow=2, 	//结束行
total=6, 		//总条数
pages=3, 		//总页数
list=Page{
    
    count=true, pageNum=1, pageSize=2, startRow=0, endRow=2, total=6, pages=3, reasonable=false, pageSizeZero=false}, 
prePage=0, 	//首页
nextPage=2, 	//下一页
isFirstPage=true, 	//是第一页
isLastPage=false,	// 是最后一页
hasPreviousPage=false, 	//有上一页
hasNextPage=true, 		//有下一页
navigatePages=2, 		//导航页数
navigateFirstPage=1, 	//导航到第一页
navigateLastPage=2,  	//导航到最后一页
navigatepageNums=[1, 2]}	//导航 页数 页码

1.2 使用步骤

  1. 导入依赖
<!--pageHelper-->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.1.4</version>
</dependency>
  1. 配置mybatis-config.xml

在mybatis-config.xml中配置,注意顺序问题

<!-- 配置分页插件 -->
<plugins>
    <plugin interceptor="com.github.pagehelper.PageHelper">
        <!-- 设置数据库类型-->
        <property name="dialect" value="mysql"/>
    </plugin>
</plugins>
  1. 接口
List<User> queryAllUser();
  1. Mapper

一定注意,不要在SQL语句后面加分号,否则MyBatis不能动态的正确拼接limt 分页语句

<select id="queryAllUser" resultMap="userMap">
    select * from user
</select>
  1. 测试
@Test
public void queryAllUser() throws IOException {
    
    
    // 读取配置文件mybatis-config.xml
    InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
    // 根据配置文件构建SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
    // 通过SqlSessionFactory创建SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    // 开启分页,pageNum表示当前页码,pageSize表示每页数据条数
    PageHelper.startPage(2,2);
    // 获取数据
    List<User> userList = mapper.queryAllUser();
    // 把数据封装在pageInfo对象中,后期可以通过这种方式返回给前端,进行分页展示
    PageInfo<User> userPageInfo = new PageInfo<>(userList);
    System.out.println(userPageInfo);
}

十三、log4j

​ 在使用SSM进行开发时, 随着代码量的增大, 配置信息的繁杂, 排错也随之变得越来越难. 而日志就是我们debug的有力工具,常用的日志有很多, 我们选择使用log4j,下文介绍log4j在MyBatis下的简单应用

1、使用步骤

  1. 导入依赖
<!--log4j-->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
  1. 配置mybatis-config.xml

在mybatis-config.xml中配置,注意顺序问题

<settings>
    <!-- 配置log4j日志 -->
    <setting name="logImpl" value="LOG4J"/>
</settings>
  1. 创建 文件(直接在resource文件夹下创建)
log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

十四、MyBatis缓存

​ 缓存可以将数据保存在内存中,MyBatis 提供了一级缓存和二级缓存的支持。默认情况下,MyBatis 开启二级缓存,但是并不是意味着我们之前写的所有sql都是二级缓存,要使用二级缓存需要在xml文件中使用<cache/>标签指出。

下面案例是演示配置了日志系统后,当你查询的条件一摸一样的时候只执行了一次sql。

1、一级缓存

  1. 一级缓存是基于 PerpetualCache(MyBatis自带)的 HashMap 本地缓存,作用范围为 session 域内。当 session flush(刷新)或者 close(关闭)之后,该 session 中所有的 cache(缓存)就会被清空。
  2. 在参数和 SQL 完全一样的情况下,我们使用同一个 SqlSession 对象调用同一个 mapper 的方法,往往只执行一次 SQL。因为使用 SqlSession 第一次查询后,MyBatis 会将其放在缓存中,再次查询时,如果没有刷新,并且缓存没有超时的情况下,SqlSession 会取出当前缓存的数据,而不会再次发送 SQL 到数据库。
  3. 由于 SqlSession 是相互隔离的,所以如果你使用不同的 SqlSession 对象,即使调用相同的 Mapper、参数和方法,MyBatis 还是会再次发送 SQL 到数据库执行,返回结果。

1.1 案例

  1. 保证日志开启,方便查看输出数据
  2. 接口
List<User> getUserList();
  1. Mapper
<select id="queryAllUser" resultMap="userMap">
    select * from user
</select>
  1. 测试
@Test
public void getUserList() throws IOException {
    
    
        // 读取配置文件mybatis-config.xml
        InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
        // 根据配置文件构建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
        // 通过SqlSessionFactory创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // SqlSession执行文件中定义的SQL,并返回映射结果
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        System.out.println(userList);
        List<User> userList1 = mapper.getUserList();
        System.out.println(userList1);
        System.out.println(userList1==userList);// true
}

日志打印信息

[com.hqyj.cl.mapper.UserMapper.getUserList]-==>  Preparing: select * from `user` 
[com.hqyj.cl.mapper.UserMapper.getUserList]-==> Parameters: 
[com.hqyj.cl.mapper.UserMapper.getUserList]-<==      Total: 3
[User(id=1, name=admin, password=111, age=12, deptId=0, state=1), User(id=2, name=王五, password=789, age=13, deptId=0, state=1), User(id=3, name=小王, password=123, age=14, deptId=0, state=1)]
===========================================================================================================
[User(id=1, name=admin, password=111, age=12, deptId=0, state=1), User(id=2, name=王五, password=789, age=13, deptId=0, state=1), User(id=3, name=小王, password=123, age=14, deptId=0, state=1)]

1.2 缓存失效

  • 查询不同的东西,比如同一个SQL语句,但是传递的参数不同。
  • 查询不同的Mapper.xml。
  • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存,也就是说,在两条相同语句中间插入一条其他语句(比如inset),缓存会刷新。
  • 手动清理缓存。sqlSession.clearCache()
  • 把第一个创建的sqlSession通过sqlSession.close()方法关闭后,再创建一个sqlSession,也无法实现缓存。

1.3 总结

一级缓存基本上没啥用,因为用户执行的操作出现一模一样的情况很少;通过debug可以发现,其实就是把查询出来的值存入Map集合。

2、二级缓存

二级缓存就是与namespace级别的缓存,一个名称空间对应一个缓存。

2.1 工作机制

​ 一个会话查询一条数据,这个数据会存放在当前会话的一级缓存中,当会话结束时,一级缓存就会消失,但是我们可以把当前会话数据保存在二级缓存中,新的会话查询信息就可以从二级缓存中获取内容,当然,不同的mapper查询的数据都会放在自己对应的缓存中。

2.2 格式

要启用全局的二级缓存,只需要在你的 SQL 映射文件中(XXXMapper.xml)添加一行<cache/>,比如

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

上述例子创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

配置详解

  • flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
  • size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
  • readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。

2.3 可用的清除策略

  • LRU – 最近最少使用:移除最长时间不被使用的对象默认方式。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

2.4 注意事项

  • 二级缓存是事务性的。这意味着,当 SqlSession 完成并提交时,或是完成并回滚,但没有执行 flushCache=true 的 insert/delete/update 语句时,缓存会获得更新;
  • 不能使用封装获取sqlSession对象的类;

2.5 案例

  1. 开启全局缓存(mybatis-config.xml)配置二级缓存后可以尝试不同的sqlsession执行方法,控制台只打印一条sql语句,证明

    是从缓存中取出数据

<!--开启全局缓存,默认也是开启的,但是我们一般显示定义-->
<setting name="cacheEnabled" value="true"/>

**注意事项:**在CRUD标签中,可以使用useCache属性指定是否启用二级缓存,默认true。

  1. 接口
List<User> getUserList();
  1. mapper
<!--开启二级缓存-->
<cache
       eviction="FIFO"
       flushInterval="60000"
       size="512"
       readOnly="true"/>
  1. 测试
@Test
public void getUserList() throws IOException {
    
    
    // 读取配置文件mybatis-config.xml
    InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
    // 根据配置文件构建SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
    // 通过SqlSessionFactory创建SqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // SqlSession执行文件中定义的SQL,并返回映射结果
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = mapper.getUserList();
    System.out.println(userList);
    // 关闭第一个sqlSession连接,它会把缓存放入二级缓存中
    sqlSession.close();
    System.out.println("=======================================================");
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
    List<User> userList1 = mapper1.getUserList();
    System.out.println(userList1);
    System.out.println(userList1==userList);// true
    // 关闭第二个sqlSession连接
    sqlSession1.close();
}

2.6 错误及解决

  1. 错误

如果我们在mapper文件中,直接使用<cache/>方式开启二级缓存,会报错org.apache.ibatis.cache.CacheException: Error serializing object. Cause: java.io.NotSerializableException: com.hqyj.cl.pojo.User

  1. 解决

因为要使用二级缓存需要把对应的类序列化,所以解决办法如下

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    
    
    private int id;
    private String name;
    private String password;
    private int age;
    private int deptId;
    private int state;
}

十五、MyBatis逆向工程

Mybatis 提供了一个逆向工程工具,该工具可以根据数据表自动生成针对单表的 pojo 类、mapper 映射文件和 mapper 接口。

1、使用步骤

  1. 创建数据库
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `gender` varchar(255) DEFAULT NULL,
  `phone` varchar(255) DEFAULT NULL,
  `role` varchar(255) NOT NULL DEFAULT '用户',
  `state` int(255) unsigned NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8
  1. 创建项目

新建项目,并且新建资源文件夹 config,在 config 文件夹下创建 generatorConfig.xml 文件,用于配置及指定数据库及表等。

generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <commentGenerator>
            <!-- 是否去除自动生成的注释 -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!-- Mysql数据库连接的信息:驱动类、连接地址、用户名、密码 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/servletdemo" userId="root"
                        password="112112" />

        <!-- 默认为false,把JDBC DECIMAL和NUMERIC类型解析为Integer;为true时 把JDBC DECIMAL和NUMERIC类型解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- targetProject:生成POJO类的位置 -->
        <javaModelGenerator
                targetPackage="com.hqyj.cl.pojo" targetProject="D:\workspace\mybatis\mybatis_03\src\main\java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!-- targetProject:mapper映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="com.hqyj.cl.mapper"
                         targetProject="D:\workspace\mybatis\mybatis_03\src\main\java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>

        <!-- targetProject:mapper接口生成的的位置 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.hqyj.cl.mapper" targetProject="D:\workspace\mybatis\mybatis_03\src\main\java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>

        <!-- 指定数据表 -->
        <table tableName="user"></table>
    </context>
</generatorConfiguration>

注意事项:targetProject写成绝对路径,否则可能出现路径不对,加载不出文件的情况

  1. 导入依赖
<dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-core</artifactId>
    <version>1.4.0</version>
</dependency>
  1. GeneratorSqlmap 类
package net.biancheng;

import java.io.File;
import java.util.*;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

public class GeneratorSqlMap {
    
    
    public void generator() throws Exception {
    
    
        List<String> warnings = new ArrayList<>();
        boolean overwrite = true;
        // 指定配置文件
        File configFile = new File("D:\\workspace\\mybatis\\mybatis_03\\src\\main\\resources\\config\\generator-config.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);
    }

    // 执行main方法以生成代码
    public static void main(String[] args) {
    
    
        try {
    
    
            GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap();
            generatorSqlmap.generator();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
}

注意事项:FILE文件路径写成绝对路径,相对路径可能存在路径不对的情况

2、说明

在 pojo 包中,有一部分是名字为 XxxExample 的类。类中包含以下 3 个成员变量

protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;;

以上变量说明如下:

  • distinct 字段用于指定 DISTINCT 查询。
  • orderByClause 字段用于指定 ORDER BY 条件,这个条件没有构造方法,直接通过传递字符串值指定。
  • oredCriteria 字段用于自定义查询条件。

Supongo que te gusta

Origin blog.csdn.net/ailaohuyou211/article/details/130394313
Recomendado
Clasificación