目次:
1. MyBatis の使用を開始する
1.MyBatisとは
MyBatis は、カスタム SQL、ストアド プロシージャ、高度なマッピングをサポートする優れた永続層フレームワークです。MyBatis は、ほぼすべての JDBC コードと、パラメータの設定と結果セットの取得の作業を排除します。MyBatis は、単純な XML または注釈を通じて、プリミティブ型、インターフェイス、および Java POJO (Plain Old Java Objects、Plain Old Java Objects) をデータベース内のレコードとして構成およびマッピングできます。
2、MyBatis、Hibernate、JDBC
-
Hibernate と比較すると、MyBatis はカプセル化が低いですが、パフォーマンスが優れており、サイズが小さく、学習が容易で、幅広い用途に使用できます。
-
JDBC と比較して、MyBatis はコード量を 50% 以上削減し、高い同時実行性と高い応答性の要件を満たします。
3. メリットとデメリット
3.1 利点
- MyBatis は無料でオープンソースです。
- JDBC と比較してコード量が 50% 以上削減されます。
- MyBatis は最も単純な永続化フレームワークであり、小さくて習得が簡単です。
- MyBatis は非常に柔軟であり、アプリケーションやデータベースの既存の設計に影響を与えることはありません。SQL は XML で記述され、プログラム ロジック コードから分離されているため、結合が軽減され、統合管理と最適化が促進され、コードの再利用性が向上します。
- XML タグを提供し、動的 SQL ステートメントの作成をサポートします。
- オブジェクトとデータベース間の ORM フィールド関係マッピングをサポートするマッピング タグを提供します。
- ストアド プロシージャがサポートされています。MyBatis は、ストアド プロシージャの形式で SQL をカプセル化します。これにより、ビジネス ロジックをデータベースの外部に保持し、アプリケーションの移植性を強化し、展開とテストを容易にします。
3.2 欠点
- SQL ステートメントの作成には多くの作業が必要となるため、開発者は SQL ステートメントを作成するための強固な基礎を備えている必要があります。
- SQL ステートメントはデータベースに依存しているため、データベースの移植性が低く、データベースを自由に置き換えることはできません。
3.3 使用シナリオ
MyBatis は SQL 自体に焦点を当てており、十分に柔軟な DAO レイヤー ソリューションです。インターネット プロジェクトなど、高いパフォーマンス要件があり、要件が頻繁に変更されるプロジェクトに適しています。
4. インストール
mybatis-x.x.x.jar
MyBatis を使用するには、ファイルをクラスパス (classpath) に置くだけです。Maven を使用してプロジェクトをビルドする場合は、pom.xml ファイルに次の依存関係コードを置く必要があります。
1. たとえば、Maven プロジェクトで、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. 最初の MyBatis プログラム
1. XML から SqlSessionFactory を構築する
すべての MyBatis ベースのアプリケーションは、SqlSessionFactory のインスタンスを中心としています。SqlSessionFactory のインスタンスは、SqlSessionFactoryBuilder によって取得できます。SqlSessionFactoryBuilder は、XML 構成ファイルまたは事前構成された構成インスタンスから SqlSessionFactory インスタンスを構築できます。
1.1 XML構成
設定mybatis-config.xml
ファイルには、データベース接続インスタンスを取得するためのデータ ソース (DataSource) やトランザクションのスコープと制御方法を決定するトランザクション マネージャー (TransactionManager) など、MyBatis システムのコア設定が含まれています。XML 設定ファイルの詳細については後で説明します。簡単な例を次に示します。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--在configuration配置内容时,有顺序限制-->
<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&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 注意事項
1. XML ドキュメントの正確性を検証するために使用される XML ヘッダーの宣言に注意してください。
2. マッパー要素にはマッパーのセット (マッパー) が含まれており、これらのマッパーの XML マッピング ファイルには SQL コードとマッピング定義情報が含まれています。
3. マッパーの場合、<mapper resource="mapper/UserMapper.xml"/>
XML ファイルをインポートする場合、XML ファイルが Maven プロジェクトのリソースの下にあるか、次のコンテンツを 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 SqlSessionFactoryの取得
// 读取配置文件mybatis-config.xml
InputStream config = Resources.getResourceAsStream("config/mybatis-config.xml");
// 根据配置文件构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
1.3 データベーステーブルの設計
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 JavaBeanの作成
まず、IDEA でプラグイン Lombok をダウンロードします
次に、依存関係を pom.xml にインポートします
<!--Lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
最後に、セッター、ゲッター、toString、コンストラクターの代わりにアノテーションを使用します。
@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 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 テスト
// 读取配置文件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 #{} と ${}
#{}
メソッドに値を渡すのは安全であり、プレースホルダーとして機能します。これはパラメーター プレースホルダーです。つまり、SQL インジェクションを防ぐことができる SQL プリコンパイルです。
${}
文字列の置換、つまり SQL スプライシングでは SQL インジェクションを防ぐことはできません
1.7.1 注射の場合
知らせ:
使用方法は${}
jdbc.propertiesに設定プロパティの内容を取得するので注意してください
UserMapperインターフェースに2つ以上のパラメータがある場合、パラメータが見つからない問題を解決する方法は3つあります
1. Map コレクション メソッドにカプセル化します (今のところ言うまでもありませんが、より面倒です)
2. 対応する pojo クラス オブジェクトにカプセル化します (ログイン メソッドのパラメーターは直接 User オブジェクトに置き換えられます)。
3. アノテーション @Param を使用してパラメータ名を指定し、マッパー インターフェイス メソッドを調整します
login(@Param(“ユーザー名”)文字列ユーザー名,@Param(“パスワード”)文字列パスワード)
公式推奨: パラメーターの数が 5 未満の場合はアノテーションを使用し、パラメーターの数が 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. コアオブジェクト
MyBatis には 3 つの基本要素があります。
- コアインターフェイスとクラス
- MyBatis コア構成ファイル (mybatis-config.xml)
- SQLマッピングファイル(mapper.xml)
MyBatis のコアインターフェイスとクラスは次のとおりです。
bulid() openSession()
SqlSessionFactoryBuilder ---------> sqlSessionFactory ---------------> sqlSession
すべての MyBatis アプリケーションは、SqlSessionFactory オブジェクトのインスタンスを中心にしています。
まず、SqlSessionFactoryBuilder オブジェクトを取得します。このオブジェクトは、XML 構成ファイルまたは Configuration クラスのインスタンスに従って構築できます。
次に、SqlSessionFactory オブジェクトを取得します。これは、SqlSessionFactoryBuilder オブジェクトを通じて取得できます。
SqlSessionFactory オブジェクトを使用すると、SqlSession インスタンスを取得できます。SqlSession オブジェクトには、データベースをバックグラウンドとして SQL 操作を実行するすべてのメソッドが完全に含まれており、マップされた SQL ステートメントはこのインスタンスで直接実行できます。
**各スレッドには独自の SqlSession インスタンスがあり、SqlSession のインスタンスは共有できず、スレッドセーフでもありません。したがって、SqlSession のスコープはリクエストまたはメソッド本体のスコープ内になります。
メンションリクエスト 前の段階で学習したリダイレクトと転送を思い出してください。リダイレクトは同じリクエストではなく 2 つのリクエストであり、リクエストのスコープは共有されません。
1、SqlSessionFactoryBuilder
SqlSessionFactoryBuilder は構成情報またはコードに基づいて SqlSessionFactory を生成し、複数の build() メソッド オーバーロードを提供します。これらはすべて同じ署名メソッドを呼び出します。
build(Reader reader, String environment, Properties properties)
パラメータの環境とプロパティは両方とも null にすることができるため、重複したメソッドを削除するために、実際には次のようにオーバーロードされたメソッドは 3 つだけになります。
- build(InputStream inputStream、文字列環境、Properties プロパティ)
- build(Reader リーダー、文字列環境、Properties プロパティ)
- build(構成構成)
上記の分析により、SqlSessionFactoryBuilder の build() メソッドに構成情報を、InputStream (バイト ストリーム)、Reader (文字ストリーム)、Configuration (クラス) の 3 つの形式で提供できることがわかりました。
バイト ストリームと文字ストリームの両方が構成ファイルの読み取り方法に属するため、SqlSessionFactory を構築するには 2 つの方法、つまり XML 構成ファイルの読み取りとコードの作成が容易に考えられます。これは通常、XML 構成ファイルの形式で SqlSessionFactory を構築するために使用されます。これにより、ハード コーディングを回避できる一方で、将来の構成担当者がコードを変更して繰り返しコンパイルを回避するのに便利です。
1.1 SqlSessionFactoryBuilder のライフサイクルとスコープ
SqlSessionFactoryBuilder の最大の特徴は、使用後に破棄されることです。SqlSessionFactory オブジェクトの作成後は、SqlSessionFactoryBuilder の最適なスコープがメソッド本体、つまりローカル変数に存在するため、このクラスは存在しません。
2、Sqlセッションファクトリー
SqlSessionFactory は実際のクラスではなくファクトリ インターフェイスです。彼のタスクは SqlSession を作成することです。すべての MyBatis アプリケーションは SqlSessionFactory インスタンスを中心としており、SqlSessionFactory のインスタンスは SqlSessionFactoryBuilder オブジェクトを通じて取得できます。
2.1 SqlSessionFactory のライフサイクルとスコープ
SqlSessionFactory オブジェクトが作成されると、アプリケーション全体で保持されます。これを破棄したり再作成したりする理由はなく、アプリケーションの実行中に SqlSessionFactory を複数回作成することはお勧めできません。したがって、SqlSessionFactory の最適なスコープは、アプリケーションのライフサイクルとともに存在するアプリケーションです。これは、「アプリケーションの実行時全体にわたって存在し、オブジェクト インスタンスが 1 つだけ存在する」モードであり、いわゆるシングルトン モード (実行時に 1 つだけのインスタンスを指します) です。
3、SQLセッション
SqlSession は、JDBC の Connection と同様に、永続的な操作を実行するために使用されるオブジェクトです。これは、データベースに対して SQL コマンドを実行するために必要なすべてのメソッドを提供し、SqlSession インスタンスを通じてマップされた SQL ステートメントを直接実行できます。
SqlSession には主に 2 つの用途があります。
- マッパーを入手します。マッパーに名前空間とメソッド名を通じて対応する SQL を見つけさせ、それをデータベースに送信し、実行後に結果を返します。
- マッパーを取得せずに「名前空間(名前空間) + SQL ID」で直接SQLを実行します。
3.1 SqlSession のライフサイクルとスコープ
SqlSession はデータベース セッションに対応します。データベース セッションは永続的ではないため、SqlSession のライフ サイクルも永続的ではなく、データベースにアクセスするたびに SqlSession オブジェクトを作成する必要があります。リソースを再利用するには、カプセル化方法が推奨されます。
4. 設定ファイル
最初の MyBatis プログラムでは、 MyBatis の設定ファイルを作成しましたmybatis-config.xml
。設定ファイルの内容について詳しく説明します。
1. MyBatis設定ファイルの構造
**注意事項: **mybatis-config.xml ファイル内の要素ノードには特定の順序があり、ノードの位置は上記の位置に従ってソートする必要があります。そうしないと、コンパイル エラーが発生します。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 配置 -->
<properties /><!-- 属性 -->
<settings /><!-- 设置 -->
<typeAliases /><!-- 类型命名 -->
<typeHandlers /><!-- 类型处理器 -->
<objectFactory /><!-- 对象工厂 -->
<plugins /><!-- 插件 -->
<environments><!-- 配置环境 -->
<environment><!-- 环境变量 -->
<transactionManager /><!-- 事务管理器 -->
<dataSource /><!-- 数据源 -->
</environment>
</environments>
<databaseIdProvider /><!-- 数据库厂商标识 -->
<mappers /><!-- 映射器 -->
</configuration>
1.1 構成ラベル
設定要素は XML 設定ファイル全体のルートノードであり、MyBatis の管理者に相当する役割を持ち、MyBatis のすべての設定情報が格納されます。
1.2 プロパティタグ
プロパティ タグは、リソース属性を通じて外部プロパティ ファイル (dbconfig.properties) を指定することも、プロパティ サブ要素を通じて構成することもできます。次のように
<!--驱动-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--获取连接对象地址-->
<property name="url" value="jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8"/>
<!--数据库用户名-->
<property name="username" value="root"/>
<!--数据库密码-->
<property name="password" value="112112"/>
環境ノードで上記の変数を参照します。
<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>
mybatis のバージョン 3.4.2 以降、属性のプレースホルダー (知識) を提供する機能は
デフォルトでオフになっています。設定 1 を手動で有効にすると、属性名 (db:username など) に「:」文字を使用すると
設定が有効になります。<property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>
)、または OGNL 式の三項演算子が SQL マッピングで使用されている場合
(例: table N ame ! = null ? table N ame : 'globalconstants')、区切り文字を変更するには特定の属性を設定する必要があります。属性名とデフォルト値 2. その他の設定の設定 < propertyname = " org . apache . ibatis . parsing . Property Parser .default − value − separator " value = " ? : " / > ' 3. 変更して戻りますアカウント プロパティ ' < propertyname = " username " value = " {tableName != null ? tableName : 'global_constants'})、プロパティ名とデフォルト値を区切る文字を変更するには、特定のプロパティを設定する必要があります。 2. 他の構成を設定する`<プロパティ名="org.apache.ibatis.parsing.PropertyParser .default-value-separator" value="?:"/>` 3. アカウントのプロパティを変更します` <property name="username" value="テーブル名! _ _ _ _ _=だめですか?テーブル名_ _ _ _ _:』グロバル_ _ _ _cスタントについて_ _ _ _ _' )、プロパティ名とデフォルト値を区切る文字を変更するには、特定のプロパティを設定する必要があります2、他の構成を設定する'<彼らの財産_ _ _ _ _=" or g . apache . iba t i s . parsing . Propert y Parser . default _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _−値_ _ _ _−分離または「値」_ _ _ _ _ _ _ _=「?:"/>「3.アカウント番号プロパティを変更して戻ります」<彼らの財産_ _ _ _ _=「ユーザー名」の値_ _ _ _ _=" {username?:root}"/> 4、这样,如果没有设置
` は root を使用します
1.3 設定タブ
設定タグは、MyBatis の実行時の動作を構成するために使用されます。これは、MyBatis の基本的な動作に大きな影響を与える可能性があります。一般に、多くの構成は必要なく、ほとんどの場合、そのデフォルト値を使用できます。ほとんどの場合、これを使用してログを構成し、自動ハンプ命名規則マッピングを有効にし、2 次キャッシュ (デフォルトで有効) を有効にします。
1.3.1 自動キャメルケース命名規則マッピングを有効にする
<settings>
<!-- 开启驼峰命名规则 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
1.3.2 設定ログ
<settings>
<!-- 配置log4j日志 -->
<setting name="logImpl" value="LOG4J"/>
</settings>
1.3.3 L2 キャッシュを有効にする
<settings>
<!--开启二级缓存,默认是开启的,显示定义出来-->
<setting name="cacheEnabled" value="true"/>
</settings>
1.4 typeAliases タグ
クラスの完全修飾名をどこでも指定しないようにするには、typeAliases タグを使用してエイリアスを定義します。2つの方法に分かれます:
- クラスのエイリアス
<typeAliases>
<!--方式一,逐个设置,大小写不受影响-->
<typeAlias type="com.hqyj.cl.pojo.User" alias="User"/>
<typeAlias type="com.hqyj.cl.pojo.Person" alias="Person"/>
</typeAliases>
- フォルダーの内容のエイリアス
<typeAliases>
<!--方式二,统一设置
在没有注解@Alias()的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。
比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值-->
<package name="com.hqyj.cl.pojo"/>
</typeAliases>
1.5 typeHandlers タグ
typeHandlers は主に取得した値を合理的に Java 型に変換します。typeHandler では jdbcType と javaType に分かれており、jdbcType はデータベースの型を定義するために使用され、javaType は Java の型を定義するために使用され、typeHandler の役割は jdbcType と javaType の間の相互変換を引き受けることです。MyBatis にはデフォルトのタイプ ハンドラーがあるため、手動で設定する必要はありません。
1.6 環境ラベル
[環境] タブでは、SQL を複数の異なるデータベースにマップするように MyBatis の複数のオペレーティング環境セットを構成できます。デフォルトの動作環境(デフォルトで指定されている)を指定する必要がありますが、現時点では MySQL のセットを設定するだけで済みます。
1.6.1transactionManagerタグ
MyBatis は、JDBC と MANAGED という 2 つのトランザクション マネージャーをサポートします。ここではJDBCを選択します。
1.6.2 dataSourceタグ
接続先のデータベースのドライバー名、URL、ユーザー名とパスワードなど、データベースの接続プロパティを構成するために使用されます。3 つの値 (UNPOOLED、POOLED、JNDI) がありますが、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.7resultMap マッピング (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 マッパータグ
マッパータグは、MyBatis SQL マッピング ファイルのパスを指定するために使用されます。
1.9.1 マッパーラベル
マッパーはマッパーのサブタグです。マッパーのリソース属性は、SQL マッピング ファイルのパス (クラス リソース パス) を指定するために使用されます。多くの方法がありますが、ここではそのうちの 3 つを使用します
<!--映射器,映射器的 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>
5、Mapper(マッパー)
マッパーは MyBatis で最も重要なファイルであり、マッピング ステートメントまたはマッピング SQL ステートメントと呼ばれる一連の SQL ステートメント (クエリ、追加、削除、変更など) が含まれています。
マッパーは Java インターフェースと XML ファイル (またはアノテーション) で構成され、その機能は次のとおりです。
- パラメータのタイプを定義する
- キャッシュを構成します。デフォルトは一次キャッシュです。
- SQL文と動的SQLを提供する
- クエリ結果とPOJOの間のマッピング関係を定義する
マッパーには次の 2 つの実装があります。
- これは、mybatis-config.xml ファイルで説明する XML ファイルなど、マッパーの生成に使用される XML ファイルによって実現されます。おすすめの方法。
- アノテーションによって実現され、Configuration オブジェクトを使用して Mapper インターフェイスを登録します。
1. XML実装マッパー
XML 定義マッパーは、インターフェイスと XML の 2 つの部分に分かれています。
1.1 インターフェースを定義する
public interface UserMapper {
List<User> getUserList();
}
1.2 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 説明
- namespace は、定義されたインターフェイスの完全修飾名と一致する名前空間を定義するために使用されます。
<select>
この要素は、これがクエリ ステートメントであることを示し、属性 ID はこの SQL を識別するために使用されます。resultType は、返される値が User 型の値であることを示します。
1.3 MyBatis設定ファイルを変更する
次のコードを MyBatis 構成ファイルに追加します。
<!--该语句用来引入 XML 文件,MyBatis 会读取 UserMapper.xml 文件,生成映射器-->
<mapper resource="com/hqyj/cl/mapper/UserMapper.xml"/>
1.4 テストコード
@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. アノテーションはマッパーを実装します
アノテーションを使用してマッパーを実装するには、インターフェイスで Java アノテーションを使用し、SQL を挿入するだけで済みます。
2.1 テストコード
public interface UserMapper {
@Select(value = "select * from user")
public List<User> getUserList();
}
2.1.1 説明
- @Select アノテーションを使用し、XML と同じ選択ステートメントを挿入しました。
- アノテーションと XML ファイルの両方を使用して同時に定義すると、XML メソッドがアノテーション メソッドをオーバーライドします。(1 つの構成方法のみを使用すると、エラーが報告される可能性があります)
- 単純なステートメントの場合は注釈を使用でき、複雑なステートメントの場合は XML を使用することをお勧めします。
3. MyBatis マッパーの主な要素
追跡調査で一つ一つ解説していきます
要素名 | 説明する | 述べる |
---|---|---|
マッパー | マッピング ファイルのルート ノード。namespace という名前の属性が 1 つだけあります。 | 名前空間の役割は次のとおりです。名前空間は、さまざまなマッパーを区別するために使用され、DAO インターフェイス、つまりインターフェイス指向プログラミングをグローバルに一意にバインドします。名前空間がインターフェイスにバインドされている場合、インターフェイスの実装クラスを記述する必要はありません。MyBatis は、SQL ステートメントを実行するインターフェイスの完全修飾名を通じて、対応するマッパー設定を検索します。したがって、名前空間の名前はインターフェイスの名前と同じである必要があります。 |
選択する | クエリ ステートメント。最も一般的に使用され、最も複雑な要素の 1 つ | パラメータをカスタマイズしたり、結果セットを返したりすることができます。 |
入れる | 挿入ステートメント | 実行後に、挿入された項目の数を表す整数を返します。 |
アップデート | 更新ステートメント | 実行後に、更新されたアイテムの数を表す整数を返します。 |
消去 | ステートメントの削除 | 実行後に、削除されたアイテムの数を表す整数を返します。 |
パラメータマップ | パラメータのマッピング関係を定義する | 削除される要素、非推奨です |
SQL | SQL の一部を定義し、どこでもそれを参照できるようにします。 | たとえば、テーブルの列名を一度定義すると、複数の SQL ステートメントで使用できます。 |
結果マップ | データベースの結果セットとオブジェクト間の対応関係を記述するために使用され、最も複雑かつ強力な要素です。 | マッピングルールを提供する |
キャッシュ | 指定された名前空間のキャッシュを構成する | - |
キャッシュ参照 | 他の名前空間キャッシュ構成への参照 | - |
6、MyBatis は 2 つの方法で SQL を実行します
MyBatis には、次の 2 つの方法で SQL ステートメントを実行できます。
- SqlSession を介して SQL を送信する
- SqlSession を通じて Mapper インターフェイスを取得し、Mapper インターフェイスを通じて SQL を送信します
1、SQLセッション
マッパーがあれば、SqlSession を介して SQL を送信できます。MyBatis には、selectOne と selectList という 2 つの一般的なクエリ メソッドがあります。
1.1 セレクトワン
selectOne メソッドは、クエリが使用され、オブジェクトが 1 つだけ返されること、およびクエリ条件を指定する必要があることを示します。クエリできるのは 0 または 1 レコードのみで、複数のレコードがある場合は操作エラーが発生します。一般的な形式は次のとおりです (他のオーバーロード方法もありますので、必要に応じて選択してください)
sqlSession.selectOne(String arg0, Object arg1)
1.2 選択リスト
selectList メソッドはクエリを表し、リストを返します。0 または N 個のレコードをクエリできます。一般的なフォーマットは次のとおりです
sqlSession.selectList(String arg0, Object arg1)
1.3 説明
- 上記の構文形式では、String オブジェクトは名前空間と SQL ID で構成されており、MyBatis が対応する SQL を見つけることができるように、SQL を完全に特定します。Object オブジェクトは、渡す必要があるパラメータ、つまりクエリ条件です。
- selectOne によって実装される selectList は実装できます。つまり、リストにはオブジェクトが 1 つだけ存在します。ただし、selectList で達成できることは、selectOne では達成できない可能性があります。
- MyBatis に getUserList という ID を持つ SQL が 1 つだけある場合は、パッケージのパス名を削除できます。
2. マッパーインターフェース
以下に示すように、SqlSession はマッパー インターフェイスを取得し、マッパー インターフェイスを介して SQL を送信することもできます。
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
2.1 説明
- SqlSession の getMapper メソッドを通じて Mapper インターフェイスを取得し、そのメソッドを呼び出します。XML ファイルやインターフェースアノテーションで定義された SQL は「クラスの完全修飾名 + メソッド名」で検索できるため、MyBatis では該当する SQL を実行して結果を返すことができます。
セブン、CRUDレーベル
クエリ操作のみが戻り結果の型をそれに応じて指定する必要があるため、select タグのみが resultType 属性を持ちます。
1.タグを選択
MyBatis では、select タグは、クエリ操作を実行するために最も一般的に使用される強力な SQL 言語タグです。形式は次のとおりです
<select id="queryUserByUsername" resultType="user" parameterType="string">
select * from `user` where `username` like concat ('%',#{username},'%')
</select>
1.1 説明
- パラメータは SQL ステートメントの実行時に定義でき、パラメータには int、float、String などの単純なパラメータ タイプ、または JavaBean、Map などの複雑なパラメータ タイプを使用できます。MyBatis は強力なマッピング ルールを提供しており、SQL の実行後、MyBatis は結果セットを JavaBean に自動的にマッピングします。
- データベースのクエリ結果と戻り値の型の属性を自動的に照合するために、通常、同じ一連の命名規則が MySQL データベースと JavaBean に使用されます。つまり、Java の命名ハンプ規則です。そのため、マッピングは行われません。必須 (データベーステーブルのフィールド名と属性。名前が一致しない場合は手動マッピングが必要です)
- パラメータの受け渡しと使用は、
#{参数名}
MyBatis に PreparedStatement パラメータを生成するよう指示することと同じです。
1.2 共通のプロパティ
属性名 | 説明する | 述べる |
---|---|---|
ID | これは Mapper の名前空間と組み合わせて使用され、MyBatis が呼び出すための一意の識別子です。 | 名前空間 + ID が一意でない場合、MyBatis は例外をスローします。 |
パラメータの種類 | 受信 SQL ステートメントの受信パラメーター タイプの完全修飾名または別名を示します。これはオプションの属性であり、MyBatis は特定の受信ステートメントのパラメーターを推測できます。 | 基本的なデータ型と JavaBean や Map などの複雑なデータ型をサポート |
結果の種類 | SQL ステートメントの実行後に返される型 (完全修飾名または別名)。コレクション型の場合、コレクション要素の型が返され、返すときに resultType または resultMap のいずれかを使用できます。 | - |
結果マップ | <resultMap> これは要素とともに使用されるマッピング セットへの参照であり、resultType または resultMap のいずれかで返されます。 |
これは MyBatis の最も複雑な要素であり、マッピング ルール、カスケード、typeHandler などを構成できます。 |
フラッシュキャッシュ | SQL ステートメントを呼び出した後、MyBatis が前のクエリのローカル キャッシュと 2 次キャッシュをクリアすることを要求するかどうかを設定するために使用されます。 | デフォルト値は false です。true に設定すると、SQL ステートメントが呼び出されるたびにローカル キャッシュと 2 次キャッシュがクリアされます。 |
キャッシュを使用する | 2 次キャッシュのスイッチを有効にします。デフォルト値は true です。これは、クエリ結果が 2 次キャッシュに保存されることを意味します。 | - |
タイムアウト | タイムアウト パラメータの設定に使用されます。単位は秒です。タイムアウトが経過すると例外がスローされます。 | - |
フェッチサイズ | 設定されているレコードの総数を取得する | デフォルト値は、データベース製造元が提供する JDBC ドライバーによって設定された番号です。 |
ステートメントの種類 | MyBatis にどの JDBC ステートメントを処理するかを指示します。値は STATEMENT (Statement)、PREPARED (PreparedStatement)、CALLABLE (CallableStatement) です。 | - |
結果セットの種類 | これは JDBC の ResultSet インターフェイス用であり、その値は FORWARD_ONLY (前方アクセスのみを許可)、SCROLL_SENSITIVE (双方向スクロール、ただし時間内に更新されない)、SCROLLJNSENSITIVE (双方向スクロール、タイムリーな更新) に設定できます。 | - |
1.3 複数のパラメータ
場合によっては、ユーザー ログインなどの SQL ステートメントを実行するために複数のパラメータを渡す必要があります。現時点では、それを実現するには 3 つの方法があります。つまり、Map を使用してパラメータを渡す、アノテーションを使用してパラメータを渡す、および JavaBean を使用してパラメータを渡すです。 ; パフォーマンスなどを考慮して、パラメータを渡すために Map を使用することはお勧めできません。そこで、後者の 2 つのケースを分析します。
1.3.1 アノテーションを使用してパラメータを渡す
以下に示すように、MyBatis のアノテーション @Param() を使用してパラメータを渡します。
1.3.1.2 ケース
- インターフェース
//用户登录
User login(@Param("username")String username,@Param("password")String password);
- マッパー
<!--用户登录-->
<select id="login" resultType="User">
select * from user where username = #{username} and password = #{password}
</select>
1.3.1.2 説明
パラメーターをバックグラウンドに渡すと、MyBatis は @Param によって提供された名前を通じて #{name} が name パラメーターを表すことを認識し、パラメーターの可読性を向上させます。ただし、この SQL に 10 個のパラメーターを含むクエリがある場合、可読性が低下し、コードが複雑になります。
1.3.2 JavaBean を使用してパラメータを渡す
パラメータが多すぎる場合、MyBatis では JavaBean を整理し、読みやすさを向上させるために単純な setter および getter メソッドを通じてパラメータを設定できます。次のように
1.3.2.1 ケース
- インターフェース
//增加用户
int selectUser(User user);
- マッパー
<!--增加用户-->
<select id="selectUser" resultType="User">
select * from user where username = #{username} and password = #{password} and position = #{position}
</select>
1.3.3 相違点
上記 2 つの方法の違いは次のとおりです。
- @Param アノテーションを使用してパラメータを渡すと、パラメータの数が影響を受けます。n≤5 の場合は、より直観的であるため、パラメータを渡す最良の方法です。n>5 の場合、複数のパラメータがあると呼び出しに困難が生じます。
- パラメータの数が 5 を超える場合は、JavaBean メソッドを使用することをお勧めします。
2.タグを挿入
MyBatis の挿入タグは、挿入ステートメントを定義し、挿入操作を実行するために使用されます。MyBatis が挿入ステートメントを実行すると、データベースに影響を与える行数が返されます。
2.1 事例
挿入タグによるユーザー関数の追加
- インターフェース
//增加用户
int addUser(User user);
- マッパー
<!--增加用户-->
<insert id="addUser">
insert into user values (null,#{username},#{password},#{userPhone},#{createTime},#{position})
</insert>
テストクラス
sqlSession.commit(); コミットが必要です
2.2 共通の属性
属性名 | 説明する | 述べる |
---|---|---|
ID | これは Mapper の名前空間と組み合わせて使用され、MyBatis が呼び出すための一意の識別子です。 | 名前空間 + ID が一意でない場合、MyBatis は例外をスローします |
パラメータの種類 | SQL ステートメントに渡されるパラメーター タイプの完全修飾名または別名。オプションの属性です。 | 基本的なデータ型と JavaBean や Map などの複雑なデータ型をサポート |
keyProperty | この属性の機能は、挿入操作の戻り値を PO クラスの属性 (通常は主キーに対応する属性) に割り当てることです。結合主キーの場合は、複数の値をカンマで区切って指定できます。 | - |
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 案例
- 接口
//通过用户姓名修改用户
int updateUserByUserName(User user);
- 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 案例
- 接口
//删除某个用户
int delUserById(int id);
- 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存储结果集
不推荐使用该方式
- 接口
// 用户列表
List<Map<String,Object>> queryAllUser();
- Mapper
<select id="selectAllUser" resultType="map">
select * from `user`
</select>
**注意事项:**Map 的 key 是 select 语句查询的字段名(必须完全一样),而 Map 的 value 是查询返回结果中字段对应的值,一条记录映射到一个 Map 对象中。
1.2.2 使用POJO存储结果集
推荐使用该方式
- POJO类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String username;
private String password;
}
- 接口
public interface UserMapper {
List<User> getUserList();
}
- 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 说明
- resultMap 元素的属性 id 代表这个 resultMap 的标识,type 标识需要映射的 POJO。我们可以使用 MyBatis 定义好的类的别名或自定义类的全限定名。
- 使用 property 元素指定 User的属性名称 username,column 表示数据库中 user表的 SQL 列名 username,将 POJO 和 SQL 的查询结果一 一对应。
- MyBatis 的每一个查询映射的返回类型都是 resultMap,只是当我们提供的返回类型是 resultType 时,MyBatis 会自动把对应的值赋给 resultType 所指定对象的属性,而当我们提供的返回类型是 resultMap 时,MyBatis 会将数据库中的列数据复制到对象的相应属性上,可用于复制查询。
- 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三个类
- Student类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private int id;
private String studentName;
private Addr addr;
private List<Teacher> teacher;
}
- Addr类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Addr {
private int id;
private String addr;
}
- 接口
List<Student> selectAllStudent();
- 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>
- 测试
@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 集合属性中。示例代码如下
- Teacher类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
private int id;
private String teacherName;
}
- 接口
List<Student> selectAllStudent();
- 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>
- 测试
@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 案例
- 接口
List<User> selectAllUser(User user);
- 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>
- 测试
@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 案例
- 接口
List<User> selectAllUser(User user);
- 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>
- 测试
@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 案例
- 接口
List<User> selectAllUser(User user);
- 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>
- 测试
@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 案例
- 接口
int updateUser(User user);
- 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>
- 测试
@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 案例
- 接口
List<User> selectUser(List<Integer> ageList);
- 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>
- 测试
@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 案例
- 接口
List<User> queryUser(String name);
- Mapper
<select id="queryUser" resultMap="userMap">
<bind name="pattern" value="'%'+_parameter+'%'" />
SELECT * FROM `user`
WHERE name like #{pattern}
</select>
- 测试
@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 案例
- 接口
List<User> selectAllUser(User user);
- 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>
- 测试
@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 使用步骤
- 导入依赖
<!--pageHelper-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.4</version>
</dependency>
- 配置mybatis-config.xml
在mybatis-config.xml中配置,注意顺序问题
<!-- 配置分页插件 -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 设置数据库类型-->
<property name="dialect" value="mysql"/>
</plugin>
</plugins>
- 接口
List<User> queryAllUser();
- Mapper
一定注意,不要在SQL语句后面加分号,否则MyBatis不能动态的正确拼接limt 分页语句
<select id="queryAllUser" resultMap="userMap">
select * from user
</select>
- 测试
@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、使用步骤
- 导入依赖
<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
- 配置mybatis-config.xml
在mybatis-config.xml中配置,注意顺序问题
<settings>
<!-- 配置log4j日志 -->
<setting name="logImpl" value="LOG4J"/>
</settings>
- 创建 文件(直接在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、一级缓存
- 一级缓存是基于 PerpetualCache(MyBatis自带)的 HashMap 本地缓存,作用范围为 session 域内。当 session flush(刷新)或者 close(关闭)之后,该 session 中所有的 cache(缓存)就会被清空。
- 在参数和 SQL 完全一样的情况下,我们使用同一个 SqlSession 对象调用同一个 mapper 的方法,往往只执行一次 SQL。因为使用 SqlSession 第一次查询后,MyBatis 会将其放在缓存中,再次查询时,如果没有刷新,并且缓存没有超时的情况下,SqlSession 会取出当前缓存的数据,而不会再次发送 SQL 到数据库。
- 由于 SqlSession 是相互隔离的,所以如果你使用不同的 SqlSession 对象,即使调用相同的 Mapper、参数和方法,MyBatis 还是会再次发送 SQL 到数据库执行,返回结果。
1.1 案例
- 保证日志开启,方便查看输出数据
- 接口
List<User> getUserList();
- Mapper
<select id="queryAllUser" resultMap="userMap">
select * from user
</select>
- 测试
@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 案例
-
开启全局缓存(mybatis-config.xml)配置二级缓存后可以尝试不同的sqlsession执行方法,控制台只打印一条sql语句,证明
是从缓存中取出数据
<!--开启全局缓存,默认也是开启的,但是我们一般显示定义-->
<setting name="cacheEnabled" value="true"/>
**注意事项:**在CRUD标签中,可以使用useCache属性指定是否启用二级缓存,默认true。
- 接口
List<User> getUserList();
- mapper
<!--开启二级缓存-->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
- 测试
@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 错误及解决
- 错误
如果我们在mapper文件中,直接使用<cache/>
方式开启二级缓存,会报错org.apache.ibatis.cache.CacheException: Error serializing object. Cause: java.io.NotSerializableException: com.hqyj.cl.pojo.User
- 解决
因为要使用二级缓存需要把对应的类序列化,所以解决办法如下
@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、使用步骤
- 创建数据库
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
- 创建项目
新建项目,并且新建资源文件夹 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写成绝对路径,否则可能出现路径不对,加载不出文件的情况
- 导入依赖
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.4.0</version>
</dependency>
- 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 字段用于自定义查询条件。