mybatis入门
MyBatis
MyBatis重要核心步骤:省去了建表,写对应的实体类(可以用lombok组件)
1 | //对应实体类 |
1.创建 MyBatis 的配置⽂文件 config.xml(一般是在resources下)
1 |
|
2.通过原生接口实现
2.1Mapper.xml的编写
- MyBatis 框架需要开发者⾃自定义 SQL 语句句,写在 Mapper.xml ⽂文件中,实际开发中,会为每个实体 类创建对应的 Mapper.xml ,定义管理理该对象数据的 SQL。
1 |
|
- namespace 通常设置为⽂文件所在包+⽂文件名的形式。
- insert 标签表示执⾏行行添加操作。
- select 标签表示执⾏行行查询操作。
- update 标签表示执⾏行行更更新操作。
- delete 标签表示执⾏行行删除操作。
- id 是实际调⽤用 MyBatis 方法时需要⽤用到的参数。
- parameterType 是调⽤用对应方法时参数的数据类型
2.2注册这个mapper.xml
在全局配置⽂文件 config.xml 中注册 mapper.xml
1 | <mappers> |
2.3通过官方的接口实现类(调api)
1 | public class Test01 { |
- statement 标签可根据 SQL 执⾏行行的业务选择 insert、delete、update、select。
- 是通过mapper.xml中的namespace和id组合而成
3.自定义接口实现(推荐)
3.1自己编写接口
1 | public interface AccountRepository { |
3.2创建接口对应的 xml,就像上面的mapper.xml
MyBatis 框架会根据规则⾃自动创建接口实现类的代理理对象。
规则:
- Mapper.xml 中 namespace 为接口的全类名。
- Mapper.xml 中 statement 的 id 为接口中对应的方法名。
- Mapper.xml 中 statement 的 parameterType 和接口中对应方法的参数类型一致
- Mapper.xml 中 statement 的 resultType 和接口中对应方法的返回值类型一致。
1 |
|
3.3、在 config.xml 中注册
1 | <mappers> |
3.4 调用官方api
1 | public static void main(String[] args) { |
4.级联查询
- 样例:classes类和student类,表示classes里可以有多个学生,典型的一对多;
1 | /*classes表*/ |
1 | /*student表*/ |
1 | /*classes表对应实体*/ |
1 | /*Student表对应实体*/ |
4.1 一对多 ->通过学生查班级和学生
编写自定义接口
public interface StudentConfig { public Student findById (long id); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 配置对应xml
- ```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.StudentConfig.StudentConfig">
<!--namespace还是写对应的接口的全路径-->
<resultMap id="StudentMap" type="com.Student.Student">
<!--这里联合查询与一般的不一样,需要用到resultMap-->
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<association property="classes" javaType="com.Student.Classes">
<id column="cid" property="id"></id>
<result column="cname" property="name"></result>
</association>
</resultMap>
<select id="findById" parameterType="long" resultMap="StudentMap">
select s.id ,s.name,c.id cid,c.name cname from student s,classes c where s.id = #{id} and c.id =cid;
-- sql语句,通过cid联合查询
</select>
</mapper>关于这里的
resultMap下面的属性- 首先是 resultMap自身的id属性,可自定义,需要与下面的sql查询语句对应,Type就是想要最后得到的类型,因为可以从StudentConfig这个配置接口里看到所以写实体类的全路径
id就相当于是主键需要的id,然后Colum就是sql语句中的对应元素,property是原生类中的字段名称- 对于不是单一的字段就需要通过
association来联合,因为结果是一个实体类,而不是多个(多个需要用collection字段)然后就是javaType就是写实体类的对应全路径 - 在他的下面写上sql语句中对应的主键字段和原实体类中对应的字段,与之前的一样
全局config里面注册mapper
4.2 多对一 ->通过班级类查询学生
编写自定义接口
public interface ClassesConfig { public Classes findById(long id); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 配置对应xml
- ```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.StudentConfig.ClassesConfig">
<resultMap id="ClassesMap" type="com.Student.Classes">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<collection property="students" ofType="com.Student.Student">
<id column="sid" property="id"></id>
<result column="sname" property="name"></result>
</collection>
</resultMap>
<select id="findById" parameterType="long" resultMap="ClassesMap">
select s.id sid,s.name sname,c.id,c.name from student s, classes c where c.id =#{id} and cid =c.id;
</select>
</mapper>这里只将上面的
association字段换成了collection字段,其他的其实都差不多
全局config里面注册mapper
4.3多对多
样例:商品与顾客
1 | /*customer表*/ |
1 | /*goods表*/ |
1 | /*customer与goods关联表*/ |
1 | //Goods实体类 |
1 | //Customer实体类 |
编写自定义接口
public interface CustomerConfig { public Customer findById(long id); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 配置对应xml
- ```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.GoodsConfig.CustomerConfig">
<resultMap id="CustomerMap" type="com.Goods.Customer">
<id column="cid" property="id"></id>
<result column="cname" property="name"></result>
<collection property="goods" ofType="com.Goods.Goods">
<id column="gid" property="id"></id>
<result column="gname" property="name"></result>
</collection>
</resultMap>
<select id="findById" parameterType="long" resultMap="CustomerMap">
select c.id cid, c.name cname, g.id gid, g.name gname from customer c,goods g,customer_goods cg where c.id = #{id} and cg.cid =c.id and cg.gid = g.id;
</select>
</mapper>注:这里就注意哪个是结果集对应的类,要根据接口的定义来配置
全局config里面注册mapper
5.逆向工程
约束头文件
<?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">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- 导入依赖
- ```xml
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
创建 MBG 配置⽂文件 config.xml
- jdbcConnection 配置数据库连接信息。
- javaModelGenerator 配置 JavaBean 的⽣生成策略。
- sqlMapGenerator 配置 SQL 映射⽂文件⽣生成策略。
- javaClientGenerator 配置 Mapper 接⼝口的⽣生成策略。
- table 配置目标数据表。
1 |
|
context标签 id自定义,targetRuntime表示生成版本,这里创建原始版本,参数为MyBatis3targetPackage生成的在哪个包下,targetProject从哪里开始生成->这里就写从根目录下./src/main/javatableName:表名,domainObjectName:JavaBean 类名
编写对对应的主程序来实现创建逆向工程
1 | public static void main(String[] args) throws XMLParserException, IOException, InvalidConfigurationException, SQLException, InterruptedException { |
写好自己刚刚对应的配置文件的位置,其余的都是可以直接黏贴;
6.延迟加载
延迟加载也叫懒加载,针对于数据持久层的操作, 在某些特定的情况下去访问特定的数据库,从一定程度上减少了了 Java 应⽤用与数据库的交互次数。
这里拿student表做样例
在自定义接口中编写新的方法
//studentconfig接口中新增 public Student findByIdLazy(long id);1
2
3
4
- ```java
//ClassesConfig接口中新增
public Classes findByIdLazy(long id);
将一开始的级联查询拆分成两个表的分别查询
<!--ClassesConfig.xml中的新增select字段 原本的sql语句都变成了直接查询单表 --> <select id="findByIdLazy" parameterType="long" resultType="com.Student.Classes"> select *from classes where id =#{id}; </select>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- ```xml
<!--studentconfig.xml中的新增select字段
由于返回是student类所以一开始还是用resultMap存储
但是不同点就是关联另外一个表的时候,变成了select找到关联类接口中的方法,
并且通过colum元素指代将想要合并的元素与代入新查找的元素;
原本的sql语句都变成了直接查询单表
-->
<resultMap id="StudentMapLazy" type="com.Student.Student">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<!-- <association property="classes" javaType="com.Student.Classes" select="com."-->
<association property="classes" javaType="com.Student.Classes" select="com.StudentConfig.ClassesConfig.findByIdLazy" column="cid">
</association>
</resultMap>
<select id="findByIdLazy" parameterType="long" resultMap="StudentMapLazy">
select *from student where id =#{id};
</select>
测试类
public static void main(String[] args) { InputStream resourceAsStream = Test02.class.getClassLoader().getResourceAsStream("config.xml"); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream); SqlSession sqlSession = build.openSession(); StudentConfig mapper = sqlSession.getMapper(StudentConfig.class); Student byId = mapper.findByIdLazy(1); //这里先获取的是StudentConfig的类 ClassesConfig mapper1 = sqlSession.getMapper(ClassesConfig.class); Classes byIdLazy = mapper1.findByIdLazy(byId.getClasses().getId()); //通过student的实体类生成的方法,获取getClasses(class元素是原来的字段里的)元素的id System.out.println(byIdLazy); sqlSession.close(); }1
2
3
4
5
6
7
8
9
10
- 记得在全局配置里打开开关
- ```xml
<settings>
<!-- 打印SQL执行的语句-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- 开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
7.MyBatis缓存
- 第一次查询出之后会自动将该对象保存到缓存中,当下一次查询时,直接从缓存中取出对象即可, 无需再次访问数据库,减少访问次数
一级缓存:SqlSession 级别,默认开启,并且不不能关闭。
二级缓存:Mapper 级别,默认关闭,可以开启。二级缓存是多个
SqlSession共享的,范围比一级存的大
MyBatis ⾃自带的二级缓存
config.xml 配置开启二级缓存
<settings> <!-- 开启⼆二级缓存 --> <setting name="cacheEnabled" value="true"/> </settings>1
2
3
4
5
- Mapper.xml 中配置二级缓存
- ```xml
<cache></cache>
自定义接口实现序列化
implements Serializable
ehcache二级缓存导入依赖
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-core</artifactId> <version>2.4.3</version> </dependency>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- 在全局config的同一目录添加 ehcache.xml
- ```xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore/>
<defaultCache maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
config.xml 配置开启二级缓存
<settings> <!-- 开启⼆二级缓存 --> <setting name="cacheEnabled" value="true"/> </settings>1
2
3
4
5
6
7
8
9
10
11
12
- Mapper.xml 中配置二级缓存
- ```xml
<cache type="org.mybatis.caches.ehcache.EhcacheCache">
<!-- 缓存创建之后,最后⼀一次访问缓存的时间⾄至缓存失效的时间间隔 -->
<property name="timeToIdleSeconds" value="3600"/>
<!-- 缓存⾃自创建时间起⾄至失效的时间间隔 -->
<property name="timeToLiveSeconds" value="3600"/>
<!-- 缓存回收策略略,LRU表示移除近期使⽤用最少的对象 -->
<property name="memoryStoreEvictionPolicy" value="LRU"/>
</cache>
实体类不需要实现序列列化接口。
8.动态SQL
简单来说就是标签的使用,if,where,choose,when,trim,set,foreach
| 标签名 | 作用 |
|---|---|
| if | if 标签可以自动根据表达式的结果来决定是否将对应的语句添加到 SQL 中,如果条件不成立则不添加, 如果条件成⽴立则添加 |
| where | where 标签可以自动判断是否要删除语句句块中的 and 关键字,如果检测到 where 直接跟 and 拼接,则自动删除 and,通常情况下 if 和 where 结合起来使用 |
| choose when | 类似于if和where的连用 |
| trim | trim 标签中的 prefix 和 suffix 属性会被⽤用于生成实际的 SQL 语句句会和标签内部的语句进行接,如 果语句前后出现了了 prefixOverrides 或者 suffixOverrides 属性中指定的值,MyBatis 框架会⾃自动将其删除。 |
| set | set 标签⽤用于 update 操作,会⾃自动根据参数选择⽣生成 SQL 语句句 |
| foreach | foreach 标签可以迭代⽣生成⼀一系列列值,这个标签主要⽤用于 SQL 的 in 语句句 |
if、where正常都一起用
接口里自定义方法
public Account findByAccount(Account account);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- xml里编写相应的sql语句
- ```xml
<select id="findByAccount" resultType="com.Account.Account" parameterType="com.Account.Account">
select *from account
<where>
<if test="id!=0"> and id= #{id}</if>
<if test="username!=null">
and username = #{username}
</if>
<if test="password">
and password = #{password}
</if>
<if test="age!=0">
and age = #{age}
</if>
</where>
</select>就是如果查找的时候少参数的话,依旧可以凭借提供的参数查找,而不需要写四条sql语句一一对应,很像java中的方法重载
when、choose其实和ifwhere一样
与上面同一个方法
xml中sql语句
<select id="findByAccount" resultType="com.Account.Account" parameterType="com.Account.Account"> select *from account <where> <choose> <when test="id!=0"> and id= #{id} </when> <when test="username!=null"> and username = #{username} </when> <when test="password!=null"> and password =#{password} </when> <when test="age!=0"> and age =#{age} </when> </choose> </where> </select>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- 所以选择if,where连用就好啦
- trim
- 与上面同方法
- xml中sql
- ```xml
<select id="findByAccount" resultType="com.Account.Account" parameterType="com.Account.Account">
select *from account
<trim prefix="where" prefixOverrides="and">
<if test="id!=0">
and id= #{id}
</if>
<if test="username !=null">
and username =#{username}
</if>
<if test="password!=null">
and password=#{password}
</if>
<if test="age !=0">
and age= #{age}
</if>
</trim>
</select>就是如果有where直接与and拼接,那么框架就会自动将元素删除
set
set用于update标签所以需要接口里编写update方法
public int update (Account account);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- xml中sql
- ```xml
<update id="update" parameterType="com.Account.Account">
update account
<set>
<if test="id!=0">
and id= #{id}
</if>
<if test="username !=null">
and username =#{username}
</if>
<if test="password!=null">
and password=#{password}
</if>
<if test="age !=0">
and age= #{age}
</if>
</set>
</update>能够将真正需要改动的字段进行修改,其余字段不会变,原来的直接update是所有的字段重新覆盖所以效率低
foreach
在原始类中添加字段
private List<Long> ids;1
2
3
4
5
- 接口中自定义方法
- ```java
public List<Account> findByIds (Account account);
xml中对应的sql











