1. mybatisの概要
1.1なぜmybatisが必要なのですか
従来、jdbcを介してデータベースに接続することには多くの欠点があります
。1。接続をロードするたびに、ドライバー名を明示的に指定する必要があります
。2。接続を取得するたびに、URL、ユーザー、パスワードなどの接続情報を指定する必要があります。3。SQL
ステートメントはJavaコードと結合されます重大
4.パラメータタイプを手動で判断する必要がある
5.結果が集中し、列名とデータタイプを手動で判断する必要がある
6.接続が使い果たされるたびに、手動で閉じる必要がある
1.2 mybatisとは
Mybatisは、jdbcパッケージに基づく準ORM永続性フレームワークであり、SQLクエリをサポートします。接続情報が構成されている限り、接続を自分で管理する必要はありません。XML構成またはアノテーションを使用してSQL操作を実行する必要性に応じて。インターフェースとpojoオブジェクトをデータベースにマップします。
1.3 mybatisの2つの概念
Mybatisは、マッピングデータテーブルのエンティティクラスオブジェクトをpojoオブジェクトとして参照します。同時に、インターフェースを作成する必要があります。インターフェースは、テーブルを操作するためのいくつかのメソッドを定義します。Mybatisは、マッピング関係に従ってデータベース内のテーブルを操作します。
1.4 mybatisのアーキテクチャ
第二に、mybatisの初期設定
2.1 pomの依存関係を導入する
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
2.2グローバル構成ファイル(mybatis-config.xml)
この構成は主に、次のようなデータベース接続情報など、mybatisの動作属性を定義します。
<?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>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis-110?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
<!-- 环境,可以配置多个,default:指定采用哪个环境 -->
<environments default="test">
<!-- id:唯一标识 -->
<environment id="test">
<!-- 事务管理器,JDBC类型的事务管理器 -->
<transactionManager type="JDBC" />
<!-- 数据源,池类型的数据源 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis-110" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
<environment id="development">
<!-- 事务管理器,JDBC类型的事务管理器 -->
<transactionManager type="JDBC" />
<!-- 数据源,池类型的数据源 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}" /> <!-- 配置了properties,所以可以直接引用 -->
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
</configuration>
サンプルテンプレート:
<?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>
<!-- 环境,可以配置多个,default:指定采用哪个环境 -->
<environments default="test">
<!-- id:唯一标识 -->
<environment id="test">
<!-- 事务管理器,JDBC类型的事务管理器 -->
<transactionManager type="JDBC" />
<!-- 数据源,池类型的数据源 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/ssmdemo" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mappers/MyMapper.xml" /> 指定mapper配置文件目录
</mappers>
</configuration>
2.3 Map.xmlを設定する
このファイルは、SQL操作を構成するために使用されます。つまり、マッパーインターフェイスのメソッドに関連するSQL操作をバインドします。など:
<?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:命名空间,随便写,一般保证命名空间唯一 -->
<mapper namespace="MyMapper">
<!-- statement,内容:sql语句。id:唯一标识,随便写,在同一个命名空间下保持唯一
resultType:sql语句查询结果集的封装类型,tb_user即为数据库中的表
-->
<select id="selectUser" resultType="com.zpc.mybatis.User">
select * from tb_user where id = #{id}
</select>
</mapper>
3、mybatisで使用される2つの方法
mybatisを使用するには、2つの方法があります。1つは従来の方法で、もう1つは動的プロキシの方法です。後者がより一般的に使用されます。
従来の方法の手順:
1. UserDaoインターフェースを作成し、実行可能なsql操作メソッドを指定します
2. UserDaoインターフェースを実装します
3. UserDaoインターフェースに対応するmapper.xml構成ファイルを記述します4.
sqlSessionオブジェクトに対応するマッパー
動的プロキシ方式:
上記と比較して、UserDaoインターフェースを実装するステップを直接省略でき、インターフェースを定義してmapper.xml構成ファイルを作成するだけで済みます。
3.1動的プロキシの完全な例
1. UserMapperインターフェースを作成します(元のUserDaoに対応)
public interface UserMapper {
/**
* 登录(直接使用注解指定传入参数名称)
* @param userName
* @param password
* @return
*/
public User login(@Param("userName") String userName, @Param("password") String password);
/**
* 根据表名查询用户信息(直接使用注解指定传入参数名称)
* @param tableName
* @return
*/
public List<User> queryUserByTableName(@Param("tableName") String tableName);
/**
* 根据Id查询用户信息
* @param id
* @return
*/
public User queryUserById(Long id);
/**
* 查询所有用户信息
* @return
*/
public List<User> queryUserAll();
/**
* 新增用户信息
* @param user
*/
public void insertUser(User user);
/**
* 根据id更新用户信息
* @param user
*/
public void updateUser(User user);
/**
* 根据id删除用户信息
* @param id
*/
public void deleteUserById(Long id);
}
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:命名空间,随便写,一般保证命名空间唯一 ,为了使用接口动态代理,这里必须是接口的全路径名-->
<mapper namespace="com.zpc.mybatis.dao.UserMapper">
<!--
1.#{},预编译的方式preparedstatement,使用占位符替换,防止sql注入,一个参数的时候,任意参数名可以接收
2.${},普通的Statement,字符串直接拼接,不可以防止sql注入,一个参数的时候,必须使用${value}接收参数
-->
<select id="queryUserByTableName" resultType="com.zpc.mybatis.pojo.User">
select * from ${tableName}
</select>
<select id="login" resultType="com.zpc.mybatis.pojo.User">
select * from tb_user where user_name = #{userName} and password = #{password}
</select>
<!-- statement,内容:sql语句。
id:唯一标识,随便写,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致
resultType:sql语句查询结果集的封装类型,使用动态代理之后和方法的返回类型一致;resultMap:二选一
parameterType:参数的类型,使用动态代理之后和方法的参数类型一致
-->
<select id="queryUserById" resultType="com.zpc.mybatis.pojo.User">
select * from tb_user where id = #{id}
</select>
<select id="queryUserAll" resultType="com.zpc.mybatis.pojo.User">
select * from tb_user
</select>
<!-- 新增的Statement
id:唯一标识,随便写,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致
parameterType:参数的类型,使用动态代理之后和方法的参数类型一致
useGeneratedKeys:开启主键回写
keyColumn:指定数据库的主键
keyProperty:主键对应的pojo属性名
-->
<insert id="insertUser" useGeneratedKeys="true" keyColumn="id" keyProperty="id"
parameterType="com.zpc.mybatis.pojo.User">
INSERT INTO tb_user (
id,
user_name,
password,
name,
age,
sex,
birthday,
created,
updated
)
VALUES
(
null,
#{userName},
#{password},
#{name},
#{age},
#{sex},
#{birthday},
NOW(),
NOW()
);
</insert>
<!--
更新的statement
id:唯一标识,随便写,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致
parameterType:参数的类型,使用动态代理之后和方法的参数类型一致
-->
<update id="updateUser" parameterType="com.zpc.mybatis.pojo.User">
UPDATE tb_user
<trim prefix="set" suffixOverrides=",">
<if test="userName!=null">user_name = #{userName},</if>
<if test="password!=null">password = #{password},</if>
<if test="name!=null">name = #{name},</if>
<if test="age!=null">age = #{age},</if>
<if test="sex!=null">sex = #{sex},</if>
<if test="birthday!=null">birthday = #{birthday},</if>
updated = now(),
</trim>
WHERE
(id = #{id});
</update>
<!--
删除的statement
id:唯一标识,随便写,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致
parameterType:参数的类型,使用动态代理之后和方法的参数类型一致
-->
<delete id="deleteUserById" parameterType="java.lang.String">
delete from tb_user where id=#{id}
</delete>
</mapper>
3.グローバル構成ファイルmybatis-config.xmlはUserMapper.xmlを導入します
<mappers>
<mapper resource="mappers/MyMapper.xml"/>
<mapper resource="mappers/UserDaoMapper.xml"/>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
4. UserMapperテストケースを作成する
import com.zpc.mybatis.dao.UserMapper;
import com.zpc.mybatis.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
public class UserMapperTest {
public UserMapper userMapper;
@Before
public void setUp() throws Exception {
// 指定配置文件
String resource = "mybatis-config.xml";
// 读取配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
// 构建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 1. 映射文件的命名空间(namespace)必须是mapper接口的全路径
// 2. 映射文件的statement的id必须和mapper接口的方法名保持一致
// 3. Statement的resultType必须和mapper接口方法的返回类型一致
// 4. statement的parameterType必须和mapper接口方法的参数类型一致(不一定)
this.userMapper = sqlSession.getMapper(UserMapper.class);
}
@Test
public void testQueryUserByTableName() {
List<User> userList = this.userMapper.queryUserByTableName("tb_user");
for (User user : userList) {
System.out.println(user);
}
}
@Test
public void testLogin() {
System.out.println(this.userMapper.login("hj", "123456"));
}
@Test
public void testQueryUserById() {
System.out.println(this.userMapper.queryUserById("1"));
}
@Test
public void testQueryUserAll() {
List<User> userList = this.userMapper.queryUserAll();
for (User user : userList) {
System.out.println(user);
}
}
@Test
public void testInsertUser() {
User user = new User();
user.setAge(20);
user.setBirthday(new Date());
user.setName("大神");
user.setPassword("123456");
user.setSex(2);
user.setUserName("bigGod222");
this.userMapper.insertUser(user);
System.out.println(user.getId());
}
@Test
public void testUpdateUser() {
User user = new User();
user.setBirthday(new Date());
user.setName("静静");
user.setPassword("123456");
user.setSex(0);
user.setUserName("Jinjin");
user.setId("1");
this.userMapper.updateUser(user);
}
@Test
public void testDeleteUserById() {
this.userMapper.deleteUserById("1");
}
}
3.2マッパーインターフェースの作成
これは主に、SQLとインターフェイスメソッド間のマッピング関係を提供します。通常、次のように記述されます。
public interface UserMapper {
public void createUser(@Param(“参数ID”) 参数类型 参数名,。。。。。)
}
@Param(“参数ID”) 这个注释是用来给传入的参数指定一个id的,然后可以给mapper.xml中的sql语句通过 #{“参数ID”}进行引用,这样就可以获取到参数的值,每一个参数都得对应一个@Param注释
3.3動的プロキシ方式で注意すべき問題
1.マッパー構成の名前空間は、
マッパーインターフェイスの完全パスと同じである必要があります2.マッパーインターフェイスのメソッド名は、select noteのidなど、SQLで定義されたIDと同じである必要があります
3.マッパーインターフェイスのメソッドの入力パラメータータイプとSQLで定義されたパラメータータイプ一貫性があります
。4。マッパーインターフェイスのメソッドの出力パラメータータイプは、SQLで定義されたresultType(場合によっては後で説明するresultMap)と一致している必要があります。
4.マッパーXML構成の詳細な説明(強調)
動的プロキシモードでは、2つの重要な記述ポイントがあります。1つはマッパーインターフェイスの準備であり、もう1つはマッパー構成ファイルの準備です。マッパー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:命名空间,随便写,一般保证命名空间唯一 ,为了使用接口动态代理,这里必须是接口的全路径名-->
<mapper namespace="com.zpc.mybatis.dao.UserMapper">
<!--
1.#{},预编译的方式preparedstatement,使用占位符替换,防止sql注入,一个参数的时候,任意参数名可以接收
2.${},普通的Statement,字符串直接拼接,不可以防止sql注入,一个参数的时候,必须使用${value}接收参数
-->
<select id="queryUserByTableName" resultType="com.zpc.mybatis.pojo.User">
select * from ${tableName}
</select>
<select id="login" resultType="com.zpc.mybatis.pojo.User">
select * from tb_user where user_name = #{userName} and password = #{password}
</select>
<!-- statement,内容:sql语句。
id:唯一标识,随便写,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致
resultType:sql语句查询结果集的封装类型,使用动态代理之后和方法的返回类型一致;resultMap:二选一
parameterType:参数的类型,使用动态代理之后和方法的参数类型一致
-->
<select id="queryUserById" resultType="com.zpc.mybatis.pojo.User">
select * from tb_user where id = #{id}
</select>
<select id="queryUserAll" resultType="com.zpc.mybatis.pojo.User">
select * from tb_user
</select>
<!-- 新增的Statement
id:唯一标识,随便写,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致
parameterType:参数的类型,使用动态代理之后和方法的参数类型一致
useGeneratedKeys:开启主键回写
keyColumn:指定数据库的主键
keyProperty:主键对应的pojo属性名
-->
<insert id="insertUser" useGeneratedKeys="true" keyColumn="id" keyProperty="id"
parameterType="com.zpc.mybatis.pojo.User">
INSERT INTO tb_user (
id,
user_name,
password,
name,
age,
sex,
birthday,
created,
updated
)
VALUES
(
null,
#{userName},
#{password},
#{name},
#{age},
#{sex},
#{birthday},
NOW(),
NOW()
);
</insert>
<!--
更新的statement
id:唯一标识,随便写,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致
parameterType:参数的类型,使用动态代理之后和方法的参数类型一致
-->
<update id="updateUser" parameterType="com.zpc.mybatis.pojo.User">
UPDATE tb_user
<trim prefix="set" suffixOverrides=",">
<if test="userName!=null">user_name = #{userName},</if>
<if test="password!=null">password = #{password},</if>
<if test="name!=null">name = #{name},</if>
<if test="age!=null">age = #{age},</if>
<if test="sex!=null">sex = #{sex},</if>
<if test="birthday!=null">birthday = #{birthday},</if>
updated = now(),
</trim>
WHERE
(id = #{id});
</update>
<!--
删除的statement
id:唯一标识,随便写,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致
parameterType:参数的类型,使用动态代理之后和方法的参数类型一致
-->
<delete id="deleteUserById" parameterType="java.lang.String">
delete from tb_user where id=#{id}
</delete>
</mapper>
4.1クラッドノートの使用
4.1.1.select
select-write
いくつかのSQLステートメントのselect属性の説明:
id属性:現在のネームスペース内のステートメントの一意の識別子。必要です。idとmapperインターフェースのメソッド名は同じである必要があります。
resultType:結果セットをjavaのオブジェクトタイプにマップします。必須(resultMapから1つ選択)
parameterType:渡されたパラメーターのタイプ。
resultMap は省略できます。返されるデータがマルチテーブルジョイントクエリなどの単一エンティティマッピングクラスでない場合は、後で詳しく説明するように、これを使用する必要があります。
4.1.2。挿入
挿入のいくつかの属性の説明:
id:一意の識別子、何気なく書く、同じ名前空間で一意に保つ、動的プロキシを使用した後、メソッド名と一致する必要があり
ますparameterType:パラメータタイプ、動的プロキシを使用した後、メソッドのパラメータタイプは一貫している
useGeneratedKeys:主キーの書き戻し
keyColumn をオンにします
:データベースの主キーを指定しますkeyProperty:
内部の主キーに対応するpojo属性名タグ:特定のSQLステートメント。
4.1.3。更新
id属性:現在のネームスペース内のステートメントの一意の識別子(必須属性)、
parameterType:渡されたパラメータータイプ、省略可能。
ラベルの内側:特定のSQLステートメント。
4.1.4.delete
削除のいくつかの属性の説明:
id属性:現在のネームスペースの下のステートメントの一意の識別子(必須属性)、
parameterType:渡されたパラメータータイプ(省略可能)。
ラベルの内側:特定のSQLステートメント。
4.2#{}と$ {}の違い
/**
* #号
* @param username1
* @return
*/
User queryUserListByName1(@Param("username1") String username1);
/**
* $号
* @param username2
* @return
*/
User queryUserListByName2(@Param("username2") String username2);
<select id="queryUserListByName1" resultType="com.zpc.mybatis.pojo.User">
select * from tb_user WHERE user_name=#{username1}
</select>
<select id="queryUserListByName2" resultType="com.zpc.mybatis.pojo.User">
select * from tb_user WHERE user_name='${username2}'//手动加了引号
</select>
#{}置き換えるだけですか?、プレースホルダーを使用してパラメーターを置き換えるPreparedStatementと同等で、SQLインジェクションを防ぐことができます。
$ {}は、SQLステートメントのステートメントに相当する文字列連結用で、文字列を使用してSQLを接続します。$は、ステートメントに渡されるSQLの任意の部分であり、SQLインジェクションを防ぐことはできません。
$ {}を使用してパラメーター値情報を取得するには、$ {value}
#{} を使用する必要があります。これはプレースホルダーを意味するだけで、パラメーターの名前とは関係ありません。パラメーターが1つしかない場合は、自動的に対応します。
4.3動的SQL(追加予定)
ifステートメント
は、それ以外の場合は
どこを選択し、
foreach を設定します
4.4 ResultMapの複雑な共同クエリの重要な属性
選択ノートで前述したように、resultTypeとresultMapを指定する必要があります。単一のテーブルをクエリすると、通常はUserテーブルなどの単一のオブジェクトが返され、クエリはUserテーブルを返します。結合クエリが複数のテーブルで実行される場合、複数のテーブルから返されたデータは、単一のエンティティークラスを使用してマッピングすることはできません。現時点では、resultTypeを使用してマップされたエンティティークラスを指定することはできません。resultMapを使用して指定する必要があります。以下はケースの説明です
4.4.1テーブルの関係の説明
この場合のビジネス関係は、ユーザー、注文、注文の詳細、および製品情報の間の関係
です
。1つの注文は1人のユーザーに対応します。1つの注文に複数の注文の詳細を含めることができます
。1つの注文の詳細には1つの製品情報が含まれます。
関連している場合:
注文とユーザーは1対1の関係にあります。
注文と注文の詳細は1対多の関係にあります。
注文と製品情報は多対多の関係にあります。
需要の説明:
1対1クエリ:注文のクエリ、
注文者の情報のクエリ1対多クエリ:注文のクエリ、
注文者の情報と注文の詳細多対多クエリ:注文のクエリ、次のクエリ個人情報と注文の詳細、および注文詳細の製品情報
4.4.2 1対1クエリ
最初に注文テーブルを作成します。
sql:
CREATE TABLE tb_order (
id int(11) NOT NULL AUTO_INCREMENT,
user_id int(11) DEFAULT NULL,
order_number varchar(255) DEFAULT NULL,
create datetime DEFAULT NULL,
updated datetime DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
实体类:
public class Order {
private Integer id;
private Long userId;
private String orderNumber;
private Date created;
private Date updated;
}
1.方法1:中心となるアイデアは、Orderオブジェクトを拡張してマッピングを完了することです。
新しいOrderUserエンティティクラスはOrderを継承します。
public class OrderUser extends Order {
private String userName;
private String password;
private String name;
private Integer age;
private Integer sex;
private Date birthday;
private Date created;
private Date updated;
}
OrderMapperインターフェース:
public interface OrderMapper {
OrderUser queryOrderUserByOrderNumber(@Param("number") String number);
}
OrderMapperの構成:
ここでは、返されたデータを継承したOrderUserでマップできるため、resultTypeを直接使用してタイプを指定できます。
<mapper namespace="com.zpc.mybatis.dao.OrderMapper">
<select id="queryOrderUserByOrderNumber" resultType="com.zpc.mybatis.pojo.OrderUser">
select * from tb_order o left join tb_user u on o.user_id=u.id where o.order_number = #{number}
</select>
</mapper>
テスト:
@Test
public void queryOrderUserByOrderNumber() throws Exception {
OrderUser orderUser = orderMapper.queryOrderUserByOrderNumber("201807010001");
System.out.println(orderUser);
}
2.方法2:オブジェクト指向の考え方。OrderオブジェクトにUserオブジェクトを追加します。メインクラスとサブクラス間の結合が低く、
OrderオブジェクトにUserプロパティを追加するために継承を介して関連付ける必要がないため、このメソッドはより頻繁に使用されます。
public class Order {
private Integer id;
private Long userId;
private String orderNumber;
private Date created;
private Date updated;
private User user;
}
マッパーインターフェイス:
/**
* 根据订单号查询订单用户的信息
* @param number
* @return
*/
Order queryOrderWithUserByOrderNumber(@Param("number") String number);
マッパー構成:
選択によって返されたデータは、単一のエンティティクラスを使用して直接マップすることはできなくなり、OrderおよびUserの2つのクラスが関係するため、resultTypeを使用して指定する必要があることに注意してください。最初に例を見てください
<resultMap id="OrderUserResultMap" type="com.zpc.mybatis.pojo.Order" autoMapping="true">
<id column="id" property="id"/>
<!--association:完成子对象的映射-->
<!--property:子对象在父对象中的属性名-->
<!--javaType:子对象的java类型-->
<!--autoMapping:完成子对象的自动映射,若开启驼峰,则按驼峰匹配-->
<association property="user" javaType="com.zpc.mybatis.pojo.User" autoMapping="true">
<id column="user_id" property="id"/>
</association>
</resultMap>
<select id="queryOrderWithUserByOrderNumber" resultMap="OrderUserResultMap"> 这里就指定resultMap为上面定义的resultMap
select * from tb_order o left join tb_user u on o.user_id=u.id where o.order_number = #{number}
</select>
テスト:
@Test
public void queryOrderWithUserByOrderNumber() throws Exception {
Order order = orderMapper.queryOrderWithUserByOrderNumber("201807010001");
System.out.println(order.getUser());
}
4.4.3メインクラスとサブクラス間でのresultMapの1対1の使用(関連付け)
<!--column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性-->
<resultMap id="唯一的标识,后面通过该id引用" type="映射的pojo对象,就是主映射类的全类名" autoMapping="true 是否根据数据库字段名和映射类的属性名称自动映射">
<id column="数据库表的主键字段,或者可以为查询语句中的别名字段" jdbcType="字段类型,可以省略" property="映射pojo对象的主键属性,就是主映射类中对应的主键的字段名" />
<!--一般来说,如果映射类中的字段名和数据库的字段名相同,一一对应的话,就会自动进行映射,不需要配置下面的result标签,因为一般会开启autoMapping-->
<result column="表的一个字段(可以为任意表的一个字段)" jdbcType="字段类型" property="映射到pojo对象的一个属性(须为type定义的pojo对象中的一个属性)"/>
<!--
association就是定义主对象和子对象的映射关系的
property :指定子对象在主对象中的字段名,也就是属性名称
javaType:子对象的类型,需要指定为全类名
autoMapping:true|false 是否按照数据库字段名和映射类的属性名称自动映射
-->
<association property="pojo的一个对象属性" javaType="pojo关联的pojo对象" >
<!--
column:指定与子对象进行关联查询的主对象的数据库表的字段,也就是主数据库表中是用哪个字段字段和子表进行关联查询的。比如说主表order用 user_id,子表User用的是id字段,那么这里指定的就应该为 user_id
jdbcType:字段类型,一般可以省略,自动映射的,这里是数据库中的类型,比如CHAR
property:指定子对象的主键属性名
如果有多个关联字段,那么就有多个对应的id标签。
-->
<id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo对象的主键属性"/>
<!--一般来说,如果映射类中的字段名和数据库的字段名相同,一一对应的话,就会自动进行映射,不需要配置下面的result标签,因为一般会开启autoMapping-->
<result column="任意表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/>
</association>
</resultMap>
4.4.4 1対多のクエリ
1対多のクエリ:クエリ順序、クエリ順序情報、およびクエリ順序の詳細。
注文順序:
public class Order {
private Integer id;
private Long userId;
private String orderNumber;
private Date created;
private Date updated;
private User user;
private List<OrderDetail> detailList;
}
上記のdetailListに注意してください。1つの注文が複数の注文の詳細に対応しているため、ここではリストを使用して複数のOrderDetailを保存しています。
Order Details OrderDetailクラス:
public class OrderDetail {
private Integer id;
private Integer orderId;
private Double totalPrice;
private Integer status;
}
マッパーインターフェイス:
/**
* 根据订单号查询订单用户的信息及订单详情
* @param number
* @return
*/
Order queryOrderWithUserAndDetailByOrderNumber(@Param("number") String number);
マッパー構成:
<resultMap id="OrderUserDetailResultMap" type="com.zpc.mybatis.pojo.Order" autoMapping="true">
<id column="id" property="id"/>
<!--collection:定义子对象集合映射-->
<!--association:完成子对象的映射-->
<!--property:子对象在父对象中的属性名-->
<!--javaType:子对象的java类型-->
<!--autoMapping:完成子对象的自动映射,若开启驼峰,则按驼峰匹配-->
<association property="user" javaType="com.zpc.mybatis.pojo.User" autoMapping="true">
<id column="user_id" property="id"/>
</association>
<!--
collection便签:用来映射集合类的,主类中的detailList
-->
<collection property="detailList" javaType="List" ofType="com.zpc.mybatis.pojo.OrderDetail" autoMapping="true">
<id column="id" property="id"/>
</collection>
</resultMap>
<select id="queryOrderWithUserAndDetailByOrderNumber" resultMap="OrderUserDetailResultMap">
select * from tb_order o
left join tb_user u on o.user_id=u.id
left join tb_orderdetail od on o.id=od.order_id
where o.order_number = #{number}
</select>
テスト:
@Test
public void queryOrderWithUserAndDetailByOrderNumber() throws Exception {
Order order = orderMapper.queryOrderWithUserAndDetailByOrderNumber("201807010001");
System.out.println(order.getUser());
System.out.println(order.getDetailList());
}
4.4.5 resultMapの使用法-メインクラスとサブクラスの1対多(コレクション)
<!--column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性-->
<resultMap id="唯一的标识,后面通过该id引用" type="映射的pojo对象,就是主映射类的全类名" autoMapping="true 是否根据数据库字段名和映射类的属性名称自动映射">
<id column="数据库表的主键字段,或者可以为查询语句中的别名字段" jdbcType="字段类型,可以省略" property="映射pojo对象的主键属性,就是主映射类中对应的主键的字段名" />
<!--一般来说,如果映射类中的字段名和数据库的字段名相同,一一对应的话,就会自动进行映射,不需要配置下面的result标签,因为一般会开启autoMapping-->
<result column="表的一个字段(可以为任意表的一个字段)" jdbcType="字段类型" property="映射到pojo对象的一个属性(须为type定义的pojo对象中的一个属性)"/>
<!--
association就是定义主对象和子对象的映射关系的一对一
property :指定子对象在主对象中的字段名,也就是属性名称
javaType:子对象的类型,需要指定为全类名
autoMapping:true|false 是否按照数据库字段名和映射类的属性名称自动映射
-->
<association property="pojo的一个对象属性" javaType="pojo关联的pojo对象" >
<!--
column:指定与子对象进行关联查询的主对象的数据库表的字段,也就是主数据库表中是用哪个字段字段和子表进行关联查询的。比如说主表order用 user_id,子表User用的是id字段,那么这里指定的就应该为 user_id
jdbcType:字段类型,一般可以省略,自动映射的
property:指定子对象的主键属性名
-->
<id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo对象的主键属性"/>
<!--一般来说,如果映射类中的字段名和数据库的字段名相同,一一对应的话,就会自动进行映射,不需要配置下面的result标签,因为一般会开启autoMapping-->
<result column="任意表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/>
</association>
<!--
当主类和子类是一对多的关系时,就需要用到collection标签,也就是集合标签
property:主类中对于子类集合对象的属性名
ofType:集合对象中子类的全类名
javaType:集合本身的类型,是list还是其他,一般可以省略
autoMapping:是否开启字段自动映射
-->
<collection property="pojo的集合属性" ofType="集合中的pojo对象" autoMapping="true">
<!--关联字段
column:主类对应的数据库表中的关联字段名
jdbcType:字段数据类型
property:子类中定义的关联属性名
如果有多个关联字段,那么就有多个对应的id标签。
-->
<id column="集合中pojo对象对应的表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" />
<!--定义除了关联字段之外的字段和子类属性的映射关联,开启automapping且名字一样可省略-->
<result column="可以为任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属性" />
</collection>
</resultMap>
複数の関連フィールドの状況については、https://www.cnblogs.com/zhengguangaa/p/9055840.htmlを参照してください
4.4.6多対多クエリ
多対多クエリ:注文のクエリ、注文情報のクエリ、注文詳細の各アイテムデータのクエリ。
製品の詳細と製品情報:
商品详情
public class OrderDetail {
private Integer id;
private Integer orderId;
private Double totalPrice;
private Integer status;
private int itemId;
private Item item;
}
商品信息
public class Item {
private Integer id;
private String itemName;
private Float itemPrice;
private String itemDetail;
}
マッパーインターフェイス:
/**
* 根据订单号查询订单用户的信息及订单详情及订单详情对应的商品信息
* @param number
* @return
*/
Order queryOrderWithUserAndDetailItemByOrderNumber(@Param("number") String number);
マッパー構成:
<resultMap id="OrderUserDetailItemResultMap" type="com.zpc.mybatis.pojo.Order" autoMapping="true">
<id column="id" property="id"/>
<association property="user" javaType="com.zpc.mybatis.pojo.User" autoMapping="true">
<id column="user_id" property="id"/>
</association>
<collection property="detailList" javaType="List" ofType="com.zpc.mybatis.pojo.OrderDetail" autoMapping="true">
<id column="detail_id" property="id"/>
<!--这里就是集合中每个商品详情都对应一个商品信息,用法和上面的一样-->
<association property="item" javaType="com.zpc.mybatis.pojo.Item" autoMapping="true">
<id column="item_id" property="id"/>
</association>
</collection>
</resultMap>
<select id="queryOrderWithUserAndDetailItemByOrderNumber" resultMap="OrderUserDetailItemResultMap">
select * ,od.id as detail_id from tb_order o
left join tb_user u on o.user_id=u.id
left join tb_orderdetail od on o.id=od.order_id
left join tb_item i on od.item_id=i.id
where o.order_number = #{number}
</select>
テスト:
@Test
public void queryOrderWithUserAndDetailItemByOrderNumber() throws Exception {
Order order = orderMapper.queryOrderWithUserAndDetailItemByOrderNumber("201807010001");
System.out.println(order);
System.out.println(order.getUser());
System.out.println(order.getDetailList());
}
5、Springboot統合mybatis
http://blog.didispace.com/spring-boot-learning-21-3-6/を参照してください
5.1 pom依存関係を追加する
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
这里的驱动按需要引入,这里以mysql为例
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
mybatis-spring-boot-starterのバージョンに関する注意:
バージョン2.1.xは、MyBatis 3.5 +、Java 8 +、Spring Boot 2.1+
2.0.xバージョンに適しています:MyBatis 3.5 +、Java
8 +、Spring Boot 2.0 / 2.1 1.3.xバージョンは、MyBatis 3.4+、 Java 6以降、Spring Boot 1.5
5.2 MySQL接続情報を追加する
MySQL接続情報をapplication.propertiesに追加します
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=xxxxx
spring.datasource.password=xxxxx
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
5.3 MySQLでターゲットテーブルを作成する
例:ID(BIGINT)、年齢(INT)、名前(VARCHAR)フィールドを含むユーザーテーブル。具体的な作成コマンドは次のとおりです。
CREATE TABLE `User` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL,
`age` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
5.4テーブルマッピングクラスの作成
たとえば、Userクラスは次のとおりです。
@Data
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
}
5.5マッパーインターフェイスの作成
たとえば、UserMapper:
public interface UserMapper {
User findByName(@Param("name") String name);
int insert(@Param("name") String name, @Param("age") Integer age);
}
5.6マッパー構成
<?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.didispace.chapter36.mapper.UserMapper">
<select id="findByName" resultType="com.didispace.chapter36.entity.User">
SELECT * FROM USER WHERE NAME = #{name}
</select>
<insert id="insert">
INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})
</insert>
</mapper>
5.6マッパーインターフェイスパッケージをスキャン場所に追加する
メインアプリケーションクラスにマッパースキャンパッケージ構成を追加します。
//使用这个注释即可,指定全包名
@MapperScan("com.didispace.chapter36.mapper")
@SpringBootApplication
public class Chapter36Application {
public static void main(String[] args) {
SpringApplication.run(Chapter36Application.class, args);
}
}
5.7 Springboot構成にマッパー構成ファイルのパスを追加する
application.propertiesに次のように追加します。
mybatis.mapper-locations=classpath:mapper/*.xml
classpath表示主类resources相对路径,上面表示resources下的mapper目录下的所有xml文件
5.8マッパーインターフェイスを使用したデータベースの操作
テスト:
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class Chapter36ApplicationTests {
//直接使用springboot的自动装载配置
@Autowired
private UserMapper userMapper;
@Test
@Rollback
public void test() throws Exception {
userMapper.insert("AAA", 20);
User u = userMapper.findByName("AAA");
Assert.assertEquals(20, u.getAge().intValue());
}
}