Explication détaillée de Mybatis (super complète)

Table des matières:

1. Premiers pas avec MyBatis

1. Qu'est-ce que MyBatis

​ MyBatis est un excellent framework de couche de persistance qui prend en charge le SQL personnalisé, les procédures stockées et le mappage avancé. MyBatis élimine presque tout le code JDBC et le travail de définition des paramètres et d'obtention des ensembles de résultats. MyBatis peut configurer et mapper des types primitifs, des interfaces et des POJO Java (Plain Old Java Objects, Plain Old Java Objects) en tant qu'enregistrements dans la base de données via de simples XML ou des annotations.

2、MyBatis、Hibernate et JDBC

  1. Comparé à Hibernate, MyBatis a une encapsulation inférieure à Hibernate, mais il a d'excellentes performances, une petite taille, facile à apprendre et une large application.

  2. Comparé à JDBC, MyBatis réduit la quantité de code de plus de 50% et répond aux exigences de haute simultanéité et de haute réponse

3. Avantages et inconvénients

3.1 Avantages

  • MyBatis est gratuit et open source.
  • Par rapport à JDBC, la quantité de code est réduite de plus de 50 %.
  • MyBatis est le framework de persistance le plus simple, petit et facile à apprendre.
  • MyBatis est assez flexible et n'imposera aucun impact sur la conception existante de l'application ou de la base de données.SQL est écrit en XML, séparé du code logique du programme, réduisant le couplage, facilitant la gestion et l'optimisation unifiées et améliorant la réutilisabilité du code.
  • Fournit des balises XML et prend en charge l'écriture d'instructions SQL dynamiques.
  • Fournit des balises de mappage pour prendre en charge le mappage des relations de champ ORM entre les objets et les bases de données.
  • Les procédures stockées sont prises en charge. MyBatis encapsule SQL sous la forme de procédures stockées, qui peuvent garder la logique métier en dehors de la base de données, améliorer la portabilité des applications et faciliter leur déploiement et leur test.

3.2 Inconvénients

  • L'écriture d'instructions SQL nécessite beaucoup de travail, ce qui nécessite que les développeurs aient une base solide dans l'écriture d'instructions SQL.
  • Les instructions SQL dépendent de la base de données, ce qui entraîne une mauvaise portabilité de la base de données et la base de données ne peut pas être remplacée à volonté.

3.3 Scénarios d'utilisation

​ MyBatis se concentre sur SQL lui-même et est une solution de couche DAO suffisamment flexible. Il convient aux projets avec des exigences de performance élevées et des changements fréquents d'exigences, tels que les projets Internet

4. Mise en place

​ Pour utiliser MyBatis, il suffit de mettre mybatis-x.x.x.jarle fichier dans le classpath (classpath). Si vous utilisez Maven pour construire le projet, vous devez mettre le code de dépendance suivant dans le fichier pom.xml

1. Par exemple, dans un projet Maven, importez les dépendances de version 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. Le premier programme MyBatis

1. Construire SqlSessionFactory à partir de XML

​ Chaque application basée sur MyBatis est centrée sur une instance de SqlSessionFactory. Une instance de SqlSessionFactory peut être obtenue par SqlSessionFactoryBuilder. Le SqlSessionFactoryBuilder peut créer une instance SqlSessionFactory à partir d'un fichier de configuration XML ou d'une instance de configuration préconfigurée.

1.1 Paramétrage XML

Le fichier de configurationmybatis-config.xml contient les paramètres de base du système MyBatis, y compris la source de données (DataSource) pour obtenir l'instance de connexion à la base de données et le gestionnaire de transactions (TransactionManager) qui détermine la portée de la transaction et la méthode de contrôle. Les détails du fichier de configuration XML seront discutés plus tard, voici un exemple 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 Précautions

1. Faites attention à la déclaration de l'en-tête XML, qui sert à vérifier l'exactitude du document XML

2. L'élément mappers contient un ensemble de mappeurs (mapper), et les fichiers de mappage XML de ces mappeurs contiennent du code SQL et des informations de définition de mappage

3. Pour les mappeurs, lors <mapper resource="mapper/UserMapper.xml"/>de l'importation de fichiers XML, soit les fichiers XML sont sous les ressources du projet maven, soit le contenu suivant doit être importé dans le fichier 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 Obtenir SqlSessionFactory

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

1.3 Table de base de données de conception

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 Ecrire JavaBean

Tout d'abord, téléchargez le plugin Lombok dans IDEA

Ensuite, importez les dépendances dans pom.xml

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

Enfin, utilisez des annotations au lieu de setters, getters, toString et constructeurs

@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 Écrire 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 Tests

// 读取配置文件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 #{} et ${}

#{}Il est sûr de passer la valeur dans la méthode, et il agit comme un espace réservé, qui est un espace réservé de paramètre ?, c'est-à-dire la précompilation sql, qui peut empêcher l'injection sql

${}Le remplacement des chaînes, c'est-à-dire l'épissage sql, ne peut pas empêcher l'injection sql

1.7.1 Boîtier d'injection

Avis:

La méthode d' utilisation ${}obtiendra le contenu de la propriété de configuration dans jdbc.properties, alors faites attention

S'il y a plus ou moins de 2 paramètres dans l'interface UserMapper, alors il y a 3 façons de résoudre le problème que les paramètres sont introuvables

1. Encapsuler dans une méthode de collecte Map (sans parler pour l'instant, c'est plus lourd)

2. Encapsuler dans un objet de classe pojo correspondant (les paramètres de la méthode de connexion sont directement remplacés par des objets utilisateur)

3. Utilisez l'annotation @Param pour spécifier le nom du paramètre pour ajuster la méthode d'interface du mappeur

​ login(@Param("username")String username,@Param("password")String password)

​Recommandation officielle : utilisez des annotations si le nombre de paramètres est inférieur à 5, et utilisez des objets si le nombre de paramètres est supérieur à 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. Objets de base

MyBatis comporte trois éléments de base :

  • Interfaces et classes principales
  • Fichier de configuration du noyau MyBatis (mybatis-config.xml)
  • Fichier de mappage SQL (mapper.xml)

Les principales interfaces et classes de MyBatis sont les suivantes

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

Chaque application MyBatis est centrée sur une instance d'un objet SqlSessionFactory.

Obtenez d'abord l'objet SqlSessionFactoryBuilder, qui peut être construit selon le fichier de configuration XML ou l'instance de la classe Configuration.

Obtenez ensuite l'objet SqlSessionFactory, qui peut être obtenu via l'objet SqlSessionFactoryBuilder.

Avec l'objet SqlSessionFactory, vous pouvez ensuite obtenir l'instance SqlSession. L'objet SqlSession contient complètement toutes les méthodes d'exécution des opérations SQL avec la base de données en arrière-plan, et l'instruction SQL mappée peut être exécutée directement avec cette instance.

**Il convient de noter que :**Chaque thread a sa propre instance SqlSession, et l'instance SqlSession ne peut pas être partagée, ni thread-safe. Par conséquent, la portée de SqlSession est dans la portée du corps de la requête ou de la méthode.

Mentionner la demande Rappeler la redirection et le renvoi appris à l'étape précédente. La redirection n'est pas la même demande, mais deux demandes, et la portée de la demande ne sera pas partagée.

1、SqlSessionFactoryBuilder

SqlSessionFactoryBuilder génère SqlSessionFactory en fonction des informations de configuration ou du code, et fournit plusieurs surcharges de méthode build(), qui appellent toutes la même méthode de signature, à savoir :

build(Reader reader, String environment, Properties properties)

Étant donné que les paramètres environnement et propriétés peuvent tous deux être nuls, pour supprimer les méthodes en double, il n'y a en fait que trois méthodes surchargées comme suit :

  • build (InputStream inputStream, environnement de chaîne, propriétés des propriétés)
  • build (lecteur de lecteur, environnement de chaîne, propriétés des propriétés)
  • construire (configuration de configuration)

Grâce à l'analyse ci-dessus, il est constaté que les informations de configuration peuvent être fournies à la méthode build () de SqlSessionFactoryBuilder sous trois formes, à savoir InputStream (flux d'octets), Reader (flux de caractères) et Configuration (classe).

Étant donné que le flux d'octets et le flux de caractères appartiennent tous deux à la manière de lire les fichiers de configuration, il est facile de penser à deux manières de créer une SqlSessionFactory, à savoir : lire les fichiers de configuration XML et écrire du code. Il est généralement utilisé pour construire SqlSessionFactory sous la forme de fichiers de configuration XML, de sorte que d'une part, le codage en dur peut être évité, et d'autre part, il est pratique pour le futur personnel de configuration de modifier et d'éviter la compilation répétée du code.

1.1 Cycle de vie et portée de SqlSessionFactoryBuilder

La plus grande caractéristique de SqlSessionFactoryBuilder est qu'il est jeté après utilisation. Une fois l'objet SqlSessionFactory créé, cette classe n'existe pas, car la meilleure portée de SqlSessionFactoryBuilder existe dans le corps de la méthode, c'est-à-dire les variables locales.

2、SqlSessionFactory

SqlSessionFactory est une interface de fabrique plutôt qu'une véritable classe. Sa tâche est de créer SqlSession ; toutes les applications MyBatis sont centrées sur l'instance SqlSessionFactory, et l'instance de SqlSessionFactory peut être obtenue via l'objet SqlSessionFactoryBuilder

2.1 Cycle de vie et portée de SqlSessionFactory

Une fois qu'un objet SqlSessionFactory est créé, il persiste dans toute l'application. Il n'y a aucune raison de le détruire ou de le recréer, et il n'est pas recommandé de créer plusieurs fois SqlSessionFactory lors de l'exécution d'une application. Par conséquent, la meilleure portée de SqlSessionFactory est Application, qui existe avec le cycle de vie de l'application. Ce mode "existe pendant toute la durée d'exécution de l'application, et il n'y a qu'une seule instance d'objet" est le mode dit singleton (se référant à une et une seule instance pendant l'exécution).

3、SqlSession

SqlSession est un objet utilisé pour effectuer des opérations persistantes, similaires à Connection dans JDBC. Il fournit toutes les méthodes nécessaires pour exécuter des commandes SQL sur la base de données et peut exécuter directement des instructions SQL mappées via l'instance SqlSession.

Il existe deux utilisations principales de SqlSession :

  1. Obtenez un mappeur. Laissez le mappeur trouver le SQL correspondant via l'espace de noms et le nom de la méthode, l'envoyer à la base de données et renvoyer le résultat après l'exécution.
  2. Exécutez SQL directement via "espace de noms (espace de noms) + identifiant SQL", sans obtenir de mappeur.

3.1 Cycle de vie et portée de SqlSession

SqlSession correspond à une session de base de données. Étant donné que la session de base de données n'est pas permanente, le cycle de vie de SqlSession n'est pas permanent et l'objet SqlSession doit être créé à chaque accès à la base de données. Les méthodes d'encapsulation sont recommandées pour récupérer les ressources.

4. Fichier de configuration

Dans le premier programme MyBatis, nous avons écrit le fichier de configuration de MyBatis mybatis-config.xml, parlons en détail du contenu du fichier de configuration

1. Structure du fichier de configuration MyBatis

**Précautions : **Les nœuds des éléments dans le fichier mybatis-config.xml ont un certain ordre, et les positions des nœuds doivent être triées selon les positions ci-dessus, sinon il y aura des erreurs de compilation.

<?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 étiquette de configuration

L'élément de configuration est le nœud racine de tout le fichier de configuration XML, et son rôle est équivalent au gestionnaire de MyBatis.Toutes les informations de configuration de MyBatis y seront stockées.

1.2 étiquette de propriétés

La balise properties peut spécifier un fichier de propriétés externe (dbconfig.properties) via l'attribut de ressource, ou elle peut être configurée via le sous-élément properties. comme suit

<!--驱动-->
<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"/>

Référencez les variables ci-dessus dans le nœud des environnements

<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 version 3.4.2 de mybatis, la fonction de mise à disposition d'attributs fictifs (connaissances)
est désactivée par défaut. Activez manuellement le paramètre
1, et activez le paramètre. <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>
Si vous utilisez le caractère ":" dans le nom de l'attribut (par exemple : db : username), ou dans L'opérateur ternaire de l'expression OGNL est utilisé dans le mapping SQL
(tel que : table Name ! = null ? table Name : 'globalconstants'), il est nécessaire de définir un attribut spécifique pour modifier le caractère en séparant le nom de l'attribut et la valeur par défaut 2. Paramètre Autre configuration' < propertyname = " org . apache . ibatis . parsing . Property Parser . default − value − separator " value = " ? : " / > ' 3. Modifier et revenir en arrière à la propriété du compte ' < propertyname = " username " value = " {tableName != null ? tableName : 'global_constants'}), vous devez définir des propriétés spécifiques pour modifier les caractères séparant le nom de la propriété et la valeur par défaut 2. Définir d'autres configuration `<property name="org.apache.ibatis.parsing.PropertyParser .default-value-separator" value=" ? :"/>` 3. Modifiez la propriété du compte` <property name="username" value="tab l e N am e ! _=n vas -tu ? Nom de la table _ _ _:g l o ba lco n s t an t s ), vous devez définir des propriétés spécifiques pour modifier le caractère séparant le nom de la propriété et la valeur par défaut2, définir d'autres configurations'<propriété d' entre eux _ _ _ _=" ou g . a p a c h e . iba t i s . parsing . P ro p er t y P a rser . d e f a u lt _ _ _ _v a l u ese p a r a t or " v a l u e=" ?:"/>'3. Modifier et revenir à la propriété du numéro de compte '<propriété d' entre eux _ _ _ _=V a l u e " nom d' utilisateur " _=" {username?:root}"/> 4、这样,如果没有设置`, est d'utiliser root

1.3 onglet paramètres

​ La balise settings est utilisée pour configurer le comportement d'exécution de MyBatis. Elle peut profondément affecter le fonctionnement sous-jacent de MyBatis. Généralement, beaucoup de configuration n'est pas nécessaire, et sa valeur par défaut peut être utilisée dans la plupart des cas. Dans la plupart des cas, utilisez-le pour configurer les journaux, activer le mappage automatique des règles de dénomination et activer le cache de second niveau (activé par défaut).

1.3.1 Activer le mappage automatique des règles d'attribution de noms de casse camel

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

1.3.2 Journal de configuration

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

1.3.3 Activer le cache L2

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

1.4 Balise typeAliases

Afin de ne pas spécifier partout le nom complet de la classe, nous pouvons définir un alias à l'aide de la balise typeAliases. Divisé en deux manières:

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

1.5 balise typeHandlers

​ typeHandlers convertit principalement la valeur acquise en un type Java raisonnablement. Dans typeHandler, il est divisé en jdbcType et javaType, parmi lesquels jdbcType est utilisé pour définir le type de base de données, et javaType est utilisé pour définir le type Java, et le rôle de typeHandler est d'entreprendre la conversion mutuelle entre jdbcType et javaType. Nous n'avons pas besoin de le définir manuellement car MyBatis a des gestionnaires de type par défaut.

1.6 étiquette des environnements

​ Dans l'onglet environnements, plusieurs ensembles d'environnements d'exploitation de MyBatis peuvent être configurés pour mapper SQL à plusieurs bases de données différentes. Un environnement d'exploitation par défaut (spécifié par défaut) doit être spécifié.Pour l'instant, nous n'avons qu'à configurer un ensemble de MySQL.

1.6.1 balise transactionManager

​ MyBatis supporte deux gestionnaires de transactions, à savoir JDBC et MANAGED. Nous choisissons JDBC.

1.6.2 balise dataSource

​ Utilisé pour configurer les propriétés de connexion de la base de données, telles que le nom du pilote, l'URL, le nom d'utilisateur et le mot de passe de la base de données à laquelle se connecter, etc. Il y a trois valeurs (UNPOOLED, POOLED, JNDI), on choisit 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>

1.7mappage resultMap (dans le fichier 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 balise de mappeurs

La balise mappers permet de spécifier le chemin du fichier de mapping SQL MyBatis.

1.9.1 étiquette de mappeur

​ mapper est une sous-balise de mappeurs. L'attribut de ressource dans mapper est utilisé pour spécifier le chemin du fichier de mappage SQL (chemin de ressource de classe). Il existe de nombreuses façons, dont trois sont utilisées ici

<!--映射器,映射器的 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>

Cinq, Mapper (cartographe)

​ Le mappeur est le fichier le plus important de MyBatis, qui contient un ensemble d'instructions SQL (telles que requête, ajout, suppression, modification), appelées instructions de mappage ou instructions SQL de mappage.

Le mappeur se compose d'une interface Java et d'un fichier XML (ou annotation), et ses fonctions sont les suivantes :

  • Définir le type de paramètre
  • Configurez le cache, la valeur par défaut est le cache de premier niveau
  • Fournir une instruction SQL et un SQL dynamique
  • Définir la relation de mappage entre les résultats de la requête et POJO

Le mappeur a les deux implémentations suivantes

  • Il est réalisé par un fichier XML, tel que le fichier XML que nous décrivons dans le fichier mybatis-config.xml, qui est utilisé pour générer le mappeur. manière recommandée.
  • Réalisé par annotation, utilisez l'objet Configuration pour enregistrer l'interface Mapper.

1. Mappeur d'implémentation XML

Le mappeur de définition XML est divisé en deux parties : interface et XML.

1.1 Définir l'interface

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

1.2 Définir 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 Descriptif

  1. namespace est utilisé pour définir un espace de noms, qui est cohérent avec le nom qualifié complet de l'interface définie.
  2. <select> L'élément indique qu'il s'agit d'une instruction de requête et l'attribut id est utilisé pour identifier ce SQL. resultType indique que ce qui est renvoyé est une valeur de type User.

1.3 Modifier le fichier de configuration MyBatis

Ajoutez le code suivant au fichier de configuration MyBatis

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

1.4 Code d'essai

@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. Annotation implémente le mappeur

Pour implémenter le mappeur à l'aide d'annotations, il vous suffit d'utiliser des annotations Java dans l'interface et d'injecter SQL

2.1 Code d'essai

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

2.1.1 Descriptif

  1. Nous avons utilisé l'annotation @Select et injecté la même instruction select que dans le XML.
  2. Si des annotations et des fichiers XML sont utilisés pour définir en même temps, la méthode XML remplacera la méthode d'annotation. (N'utilisez qu'une seule méthode de configuration et des erreurs peuvent être signalées)
  3. Pour les instructions simples, vous pouvez utiliser des annotations, et pour les instructions complexes, il est recommandé d'utiliser XML.

3. Principaux éléments du mappeur MyBatis

Il sera expliqué un par un dans l'étude de suivi

nom de l'élément décrire Remarque
mappeur Le nœud racine du fichier de mappage, avec un seul attribut nommé namespace Le rôle de l'espace de noms est le suivant : il est utilisé pour distinguer différents mappeurs et lie globalement de manière unique l'interface DAO, c'est-à-dire la programmation orientée interface. Lorsqu'un espace de noms est lié à une interface, vous n'avez pas besoin d'écrire la classe d'implémentation de l'interface, MyBatis trouvera la configuration du mappeur correspondant via le nom complet de l'interface pour exécuter l'instruction SQL. Par conséquent, le nom de l'espace de noms doit être identique au nom de l'interface.
sélectionner Instruction de requête, l'un des éléments les plus couramment utilisés et les plus complexes Vous pouvez personnaliser les paramètres, renvoyer des ensembles de résultats, etc.
insérer insérer une déclaration Renvoie un entier après exécution, représentant le nombre d'éléments insérés
mise à jour déclaration de mise à jour Renvoie un entier après exécution, représentant le nombre d'éléments mis à jour
supprimer supprimer l'instruction Renvoie un entier après exécution, représentant le nombre d'éléments supprimés
parameterMap Définir la relation de mappage des paramètres Elément à supprimer, obsolète
sql Permet de définir une partie de SQL puis de s'y référer partout Par exemple, un nom de colonne de table, nous pouvons le définir une fois et l'utiliser dans plusieurs instructions SQL
resultMap Utilisé pour décrire la correspondance entre les ensembles de résultats de la base de données et les objets, c'est l'élément le plus complexe et le plus puissant Fournir des règles de mappage
cache Configurer le cache pour un espace de noms donné -
cache-ref Références à d'autres configurations de cache d'espace de noms -

Six, MyBatis exécute SQL de deux manières

MyBatis a deux façons d'exécuter des instructions SQL, comme suit :

  1. Envoyer SQL via SqlSession
  2. Obtenez l'interface Mapper via SqlSession et envoyez SQL via l'interface Mapper

1、SqlSession

Une fois qu'il y a un mappeur, vous pouvez envoyer SQL via SqlSession.Il existe deux méthodes de requête courantes dans MyBatis, à savoir selectOne et selectList.

1.1 selectOne

La méthode selectOne indique que la requête est utilisée et qu'un seul objet est renvoyé, et la condition de requête doit être spécifiée. Seuls 0 ou 1 enregistrement peuvent être interrogés, et s'il y a plus d'un enregistrement, l'erreur de fonctionnement se produira. Les formats courants sont les suivants (il existe d'autres méthodes de surcharge, choisissez en fonction de vos besoins)

sqlSession.selectOne(String arg0, Object arg1)

1.2 sélectionnerListe

La méthode selectList représente une requête et renvoie une liste. 0 ou N enregistrements peuvent être interrogés. Les formats courants sont les suivants

sqlSession.selectList(String arg0, Object arg1)

1.3 Descriptif

  1. Dans le format de syntaxe ci-dessus, l'objet String est composé d'un espace de noms et d'un identifiant SQL, qui localise complètement un SQL, de sorte que MyBatis trouvera le SQL correspondant. L'objet Object est le paramètre qui doit être passé, c'est-à-dire la condition de requête
  2. La selectList implémentée par selectOne peut être implémentée, c'est-à-dire qu'il n'y a qu'un seul objet dans la liste. Mais ce que selectList peut réaliser, selectOne peut ne pas être en mesure de réaliser
  3. S'il n'y a qu'un seul SQL dont l'id est getUserList dans MyBatis, alors le nom du chemin du package peut être supprimé

2. Interface du mappeur

SqlSession peut également obtenir l'interface Mapper et envoyer SQL via l'interface Mapper, comme indiqué ci-dessous

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

2.1 Descriptif

  1. Obtenez une interface Mapper via la méthode getMapper de SqlSession, puis appelez ses méthodes. Comme le SQL défini par le fichier XML ou l'annotation de l'interface peut être recherché par "nom qualifié complet de la classe + nom de la méthode", MyBatis permettra au SQL correspondant de s'exécuter et de renvoyer le résultat.

Sept, label CRUD

Seule la balise select a l'attribut resultType, car seule l'opération de requête doit spécifier le type de résultat de retour en conséquence.

1. sélectionnez la balise

Dans MyBatis, la balise select est la balise du langage SQL la plus utilisée et la plus puissante pour effectuer des opérations de requête. Le format est le suivant

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

1.1 Descriptif

  1. Les paramètres peuvent être définis lors de l'exécution d'instructions SQL, et les paramètres peuvent être un type de paramètre simple, tel que int, float, String ; ou un type de paramètre complexe, tel que JavaBean, Map, etc. MyBatis fournit des règles de mappage puissantes. Après l'exécution de SQL, MyBatis mappera automatiquement le jeu de résultats sur JavaBean.
  2. Afin de faire correspondre automatiquement les résultats de la requête de la base de données avec les attributs dans le type de valeur de retour, le même ensemble de règles de nommage est généralement utilisé pour la base de données MySQL et JavaBean, c'est-à-dire la règle de nommage Java, de sorte qu'aucun mappage n'est obligatoire (noms et attributs des champs de la table de base de données Un mappage manuel est requis lorsque les noms sont incohérents)
  3. Le passage et l'utilisation de paramètres #{参数名}équivaut à indiquer à MyBatis de générer des paramètres PreparedStatement.

1.2 Propriétés communes

Nom d'attribut décrire Remarque
identifiant Il est utilisé en combinaison avec l'espace de noms de Mapper et est un identifiant unique que MyBatis appelle Si l'espace de noms + id n'est pas unique, alors MyBatis lève une exception
paramètreType Indique le nom qualifié complet ou l'alias du type de paramètre entrant de l'instruction SQL entrante. C'est un attribut facultatif, et MyBatis peut déduire les paramètres de la déclaration entrante spécifique Prend en charge les types de données de base et les types de données complexes tels que JavaBean et Map
type de résultat Type (nom qualifié complet ou alias) renvoyé après l'exécution de l'instruction SQL. S'il s'agit d'un type de collection, le type de l'élément de collection est renvoyé, et l'un de resultType ou resultMap peut être utilisé lors du retour -
resultMap Il s'agit d'une référence à un ensemble de mappages, <resultMap>utilisé avec l'élément, et peut être renvoyé avec l'un de resultType ou resultMap C'est l'élément le plus complexe de MyBatis, qui peut configurer des règles de mappage, cascade, typeHandler, etc.
flushCache Utilisé pour définir s'il faut exiger que MyBatis vide le cache local et le cache de second niveau de la requête précédente après avoir appelé l'instruction SQL La valeur par défaut est false. Si la valeur est true, le cache local et le cache de second niveau seront effacés à chaque appel de l'instruction SQL
useCache Activez le commutateur du cache de second niveau, la valeur par défaut est true, ce qui signifie que les résultats de la requête sont stockés dans le cache de second niveau -
temps mort Utilisé pour définir le paramètre de délai d'attente, l'unité est la seconde (s) et une exception sera levée à l'expiration du délai d'attente -
récupérerTaille Obtenir le nombre total d'enregistrements définis La valeur par défaut est le nombre défini par le pilote JDBC fourni par le fabricant de la base de données
instructionType Dites à MyBatis avec quelle déclaration JDBC travailler, la valeur est STATEMENT (Statement), PREPARED (PreparedStatement), CALLABLE (CallableStatement) -
resultSetType Il s'agit de l'interface ResultSet de JDBC, et sa valeur peut être définie sur FORWARD_ONLY (autorise uniquement l'accès en avant), SCROLL_SENSITIVE (défilement bidirectionnel, mais non mis à jour dans le temps), SCROLLJNSENSITIVE (défilement bidirectionnel, mise à jour en temps opportun) -

1.3 Paramètres multiples

​ Parfois, nous devons transmettre plusieurs paramètres pour exécuter des instructions SQL, telles que la connexion de l'utilisateur ; pour le moment, il existe trois façons d'y parvenir, à savoir l'utilisation de Map pour transmettre les paramètres, l'utilisation d'annotations pour transmettre les paramètres et l'utilisation de JavaBean pour transmettre les paramètres ; compte tenu des performances, etc. Question, il est déconseillé d'utiliser Map pour passer des paramètres, nous analysons donc maintenant les deux derniers cas

1.3.1 Utiliser des annotations pour passer des paramètres

Utilisez l'annotation @Param() de MyBatis pour passer des paramètres, comme indiqué ci-dessous

1.3.1.2 Cas
  1. interface
//用户登录
User login(@Param("username")String username,@Param("password")String password);
  1. Mappeur
<!--用户登录-->
<select id="login" resultType="User">
    select * from user where username = #{username} and password = #{password}
</select>
1.3.1.2 Descriptif

​ Lorsque nous passons le paramètre en arrière-plan, MyBatis saura que #{name} représente le paramètre name grâce au nom fourni par @Param, ce qui améliore la lisibilité du paramètre. Mais si ce SQL a une requête avec 10 paramètres, cela réduira la lisibilité et augmentera la complexité du code.

1.3.2 Utiliser JavaBean pour passer des paramètres

Dans le cas d'un trop grand nombre de paramètres, MyBatis permet d'organiser un JavaBean, et de définir des paramètres via de simples méthodes setter et getter pour améliorer la lisibilité. Comme suit

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

1.3.3 Différences

La différence entre les deux méthodes ci-dessus est la suivante.

  • La transmission de paramètres à l'aide de l'annotation @Param sera affectée par le nombre de paramètres. Lorsque n≤5, c'est la meilleure façon de passer des paramètres, car c'est plus intuitif ; lorsque n>5, plusieurs paramètres apporteront des difficultés à l'appel.
  • Lorsque le nombre de paramètres est supérieur à 5, il est recommandé d'utiliser la méthode JavaBean.

2. insérer une balise

La balise d'insertion MyBatis est utilisée pour définir l'instruction d'insertion et exécuter l'opération d'insertion. Lorsque MyBatis exécute une instruction d'insertion, il renvoie le nombre de lignes qu'il affecte à la base de données.

2.1 Cas

Ajouter une fonction utilisateur via insérer une balise

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

classe d'essai

sqlSession.commit(); nécessite un commit

2.2 Propriétés communes

Nom d'attribut décrire Remarque
identifiant Il est utilisé en combinaison avec l'espace de noms de Mapper et est un identifiant unique que MyBatis appelle MyBatis lève une exception si le namespace + id n'est pas unique
paramètreType Nom qualifié complet ou alias du type de paramètre transmis à l'instruction SQL, qui est un attribut facultatif. Prend en charge les types de données de base et les types de données complexes tels que JavaBean et Map
keyProperty La fonction de cet attribut est d'affecter la valeur de retour de l'opération d'insertion à un attribut de la classe PO, généralement l'attribut correspondant à la clé primaire. S'il s'agit d'une clé primaire conjointe, plusieurs valeurs peuvent être séparées par des virgules. -
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 字段用于自定义查询条件。

Je suppose que tu aimes

Origine blog.csdn.net/ailaohuyou211/article/details/130394313
conseillé
Classement