前言 终于开始学Mybatis了,其实是javaweb跳的很快,因为air师傅和其他师傅都说过jsp老化了,只需要学习一些原理即可,没必要深究,所以就直接来这了
什么是Mybatis
Mybatis是一款优秀的持久性框架
它支持定制化SQL,存储过程以及高级映射
MYbatis几乎避免了所有JDBC代码和手动设置参数以及获取结果集
Mybatis可以使用简单的XML或注解来配置和映射原生类型,接口和java的POJO(普通老式java对象)为数据库中的记录
如果获取mybatis :
一句话简单来说,Mybatis就是持久层的框架,也就是和数据库相关的框架
第一个Mybatis程序 环境搭建->导入Mybatis->编写代码->测试
环境搭建 由于和数据库有关,我们就要搭建一个MYSQL数据库 先创建一个数据库: 新建一个普通的maven项目:
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 28 29 30 31 32 33 34 35 36 37 <?xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > org.example</groupId > <artifactId > Mybatis</artifactId > <version > 1.0-SNAPSHOT</version > <properties > <maven.compiler.source > 8</maven.compiler.source > <maven.compiler.target > 8</maven.compiler.target > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > </properties > <dependencies > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.30</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.6</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.13.1</version > </dependency > </dependencies > </project >
记得把src文件夹删了,作为父工程
创建一个模块(maven项目) 这样每次子项目就不需要导包,方便很多 配置mybatis的核心配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?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 > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.cj.jdbc.Driver" > </property > <property name ="url" value ="jdbc:mysql://localhost:3306/mybatis?useSSL=true& useUnicode=true& characterEncoding=UTF-8" > </property > <property name ="username" value ="root" > </property > <property name ="password" value ="jiayou357753" > </property > </dataSource > </environment > </environments > <mappers > <mapper resource ="com/kino/dao/UserDao.xml" /> </mappers > </configuration >
其中<environment id="development">
表示环境的ID,可以有多个测试环境,然后上面一个标签有 <environments default="development">
就是默认的测试环境
<property name="url" value="${jdbc.url}"></property>
: 是我们jdbc的url:jdbc:mysql://localhost:3306
1 2 3 4 <property name="driver" value="${jdbc.driver}"></property> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"></property> <property name="username" value="root"></property> <property name="password" value="jiayou357753"></property>
URL一栏多了一些参数,分别是安全连接和编码
从 XML 中构建 SqlSessionFactory
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。 从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。
1 2 3 String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
从 SqlSessionFactory 中获取 SqlSession 既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:
1 2 3 try (SqlSession session = sqlSessionFactory.openSession()) { Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101); }
诚然,这种方式能够正常工作,对使用旧版本 MyBatis 的用户来说也比较熟悉。但现在有了一种更简洁的方式——使用和指定语句的参数和返回值相匹配的接口(比如 BlogMapper.class),现在你的代码不仅更清晰,更加类型安全,还不用担心可能出错的字符串字面值以及强制类型转换。 例如:
1 2 3 4 try (SqlSession session = sqlSessionFactory.openSession()) { BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.selectBlog(101); }
编写一个工具类 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 28 29 30 package com.Boogipop.utils;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 java.io.IOException;import java.io.InputStream;public class MybatisUtil { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "mybatis-config.xml" ; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(inputStream); } catch (IOException e) { throw new RuntimeException (e); } } public static SqlSession getSqlsession () { return sqlSessionFactory.openSession(); } }
实体类 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 28 29 30 31 32 33 34 35 36 37 38 package com.Boogipop.pojo;public class User { private int id; private String name; private String pwd; public void setId (int id) { this .id = id; } public void setName (String name) { this .name = name; } public void setPwd (String pwd) { this .pwd = pwd; } public int getId () { return id; } public String getName () { return name; } public String getPwd () { return pwd; } public User (int id, String name, String pwd) { this .id = id; this .name = name; this .pwd = pwd; } }
Dao类(操作实体类的接口) 1 2 3 4 5 6 7 8 9 10 package com.Boogipop.dao;import com.Boogipop.pojo.User;import java.util.List;public interface UserDao { List<User> getuserlist () ; }
接口实现类 这里就省去了JDBC对结果集的处理的繁琐过程了,体现Mybatis的优势 由原来的implement改为了一个mapper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.Boogipop.dao;import com.Boogipop.pojo.User;import java.util.List;public class UserDaoImp implements UserDao { @Override public List<User> getuserlist () { String sql="" } }
上面是原来的,下面是mybatis的处理方法
1 2 3 4 5 6 7 8 9 10 11 12 13 <?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 /> <mapper namespace ="com.Boogipop.dao.UserDao" > <select id ="getuserlist" resultType ="com.Boogipop.pojo.User" > -- resulttype是返回结果类型 select * from User </select > </mapper >
napespace就是Dao接口,resultType就是定义的要查询的sql对象类 这边select的id切记和之前的dao(mapper)接口的方法对应!
写一个测试类 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 package com.Boogipop.dao;import com.Boogipop.pojo.User;import com.Boogipop.utils.MybatisUtil;import org.apache.ibatis.session.SqlSession;import org.junit.Test;import java.util.List;public class UserDaotest { @Test public void test () { SqlSession sqlsession = MybatisUtil.getSqlsession(); UserDao mapper = sqlsession.getMapper(UserDao.class); List<User> getuserlist = mapper.getuserlist(); for (User user : getuserlist) { System.out.println(user); } sqlsession.close(); } }
运行过后会报错: 因为在刚开始创建mybatis-config.xml中没注册mapper: 之后又会报错初始化异常: 这是当时在Maven里讲的,由于maven约定大于配置,所以会产生配置文件无法生效的问题,解决方案就是在pom.xml(主工程和子工程)里添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <build > <resources > <resource > <directory > src/main/resources</directory > <includes > <include > **/*.properties</include > <include > **/*.xml</include > </includes > </resource > <resource > <directory > src/main/java</directory > <includes > <include > **/*.properties</include > <include > **/*.xml</include > </includes > <filtering > true</filtering > </resource > </resources > </build >
错误总结(续上面) 然后还会有几个几把错误,希望不要再犯,首先一定要检查你的mybatis-config.xml是否配置正确,其次就是上面说的maven约定大于配置的问题(还有其他解决方法,例如直接把xml配置文件放到resource文件夹,因为resource文件夹是默认配置目录) 最后是弃用方法要省略<property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
这是mybatis-config.xml配置文件中的一句话,之前是没有cj的,最后也是可以如愿得到运行结果(呼!) 给折磨坏了
测试类里执行sql第二种方法(推荐) 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 package com.kino.dao;import com.kino.pojo.User;import com.kino.utils.MybatisUtil;import org.apache.ibatis.session.SqlSession;import org.junit.Test;import java.util.List;public class UserDaotest { @Test public void test () { SqlSession sqlsession = MybatisUtil.getSqlsession(); UserDao mapper = sqlsession.getMapper(UserDao.class); List<User> list = sqlsession.selectList("com.kino.dao.UserDao.getuserlist" ); for (User user : list) { System.out.println(user); } sqlsession.close(); } }
他奶奶的第一集一个小时,我真的是日了狗了,之后再消化一下
增删改查实现(CURD) namespace(命名空间) namespace中的包名要和接口的包名一致 上面我用的是UserDao,但这次我改了个名字UserMapper:
select 查询语句嘛,我们在写UserMapper.xml的时候有个select
标签,里面有几个属性
id: 对应的就是接口中的方法名称(等效于JDBC中的实现接口)
resultType: sql执行语句的返回值类型
parameterType:参数类型
parameterType怎么用,我们写一个根据id返回结果的小Demo来学习
1 User getuserbyid (int id) ;
在这一步定义了一个接口有参方法,里面传入的形参就是我们的id
1 2 3 4 5 6 7 8 9 10 11 12 13 <?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.kino.dao.UserMapper" > <select id ="getuserlist" resultType ="com.kino.pojo.User" > select * from user </select > <select id ="getuserbyid" resultType ="com.kino.pojo.User" parameterType ="int" > select * from user where id=#{id} </select > </mapper >
Mapper.xml也添加相应的select标签和语句,这里的select标签的parameterType
就是int
,然后#{id}
就表示我们自定义的id,这是一个语法,用#{}
去包裹我们需要传入的参数,这里的#{id}
看起来和上面的形参id名称一样,实际上可以不一样,你可以#{id2}、#{number}
等等,他也算一个形参 最后再写一个测试方法:
1 2 3 4 5 6 7 8 9 @Test public void getuserbyid () { SqlSession sqlSession=MybatisUtil.getSqlsession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getuserbyid(1 ); System.out.println(user); sqlSession.close(); }
insert 1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.kino.dao;import com.kino.pojo.User;import java.util.List;public interface UserMapper { List<User> getuserlist () ; User getuserbyid (int id) ; Boolean adduser (User user) ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?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.kino.dao.UserMapper" > <select id ="getuserlist" resultType ="com.kino.pojo.User" > select * from user </select > <select id ="getuserbyid" resultType ="com.kino.pojo.User" parameterType ="int" > select * from user where id=#{id} </select > <insert id ="adduser" parameterType ="com.kino.pojo.User" > insert into mybatis.user(id,name,pwd) values(#{id},#{name},#{pwd}); </insert > </mapper >
语法后的分号可有可不有
1 2 3 4 5 6 7 8 9 10 public void adduser () { SqlSession sqlSession=MybatisUtil.getSqlsession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Boolean adduser = mapper.adduser(new User (3 , "Boogipop2" , "2662501" )); if (adduser){ System.out.println("添加成功" ); } sqlSession.commit(); sqlSession.close(); }
添加成功了
delete 和insert也是一个思路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.kino.dao;import com.kino.pojo.User;import java.util.List;public interface UserMapper { List<User> getuserlist () ; User getuserbyid (int id) ; Boolean adduser (User user) ; Boolean deluser (int id) ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?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.kino.dao.UserMapper" > <select id ="getuserlist" resultType ="com.kino.pojo.User" > select * from user </select > <select id ="getuserbyid" resultType ="com.kino.pojo.User" parameterType ="int" > select * from user where id=#{id} </select > <insert id ="adduser" parameterType ="com.kino.pojo.User" > insert into mybatis.user(id,name,pwd) values(#{id},#{name},#{pwd}); </insert > <delete id ="deluser" parameterType ="int" > delete from user where id=#{id} </delete > </mapper >
1 2 3 4 5 6 7 8 9 10 11 @Test public void deluser () { SqlSession sqlSession=MybatisUtil.getSqlsession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Boolean deluser=mapper.deluser(3 ); if (deluser){ System.out.println("删除成功" ); } sqlSession.commit(); sqlSession.close(); }
,最后也是删除成功了
update 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.kino.dao;import com.kino.pojo.User;import java.util.List;public interface UserMapper { List<User> getuserlist () ; User getuserbyid (int id) ; Boolean adduser (User user) ; Boolean deluser (int id) ; Boolean cguser (User user) ; }
1 2 3 <update id="cguser" parameterType="com.kino.pojo.User" > update user set name=#{name},pwd=#{pwd} where id=#{id} </update>
这里#{}
中的内容一定要和类中定义的名字一样
1 2 3 4 5 6 7 8 9 10 11 @Test public void cguser () { SqlSession sqlSession=MybatisUtil.getSqlsession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Boolean cguser=mapper.cguser(new User (1 ,"Kino2!" ,"asdasdasd" )); if (cguser){ System.out.println("更新成功" ); } sqlSession.commit(); sqlSession.close(); }
也是修改成功
错误排查
UserMapper.xml中不要出现什么语法错误,对应的namespace和id等等属性对应好
一句话说就是自己排查错误
Map和模糊查询 细心一点的人就发现了,假如每次参数类型都是User,咱们就不好去指定需要插入的数据或者是删除的数据。Map集合就可以很好解决这一点问题 接下来就写个小demo,用Map来添加数据
1 Boolean mapadduser (Map<String,Object> map) ;
1 2 3 <insert id ="mapadduser" parameterType ="Map" > insert into user(id,name) values(#{id},#{name}) </insert >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public void mapadduser () { SqlSession sqlSession=MybatisUtil.getSqlsession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String, Object> map=new HashMap <>(); map.put("id" ,"3" ); map.put("name" ,"asdas5da65s" ); Boolean mapadduser = mapper.mapadduser(map); if (mapadduser){ System.out.println("添加成功" ); } sqlSession.commit(); sqlSession.close(); }
添加成功了,这边Map的键要和我们的字段名称一一对应,否则会出现为null的情况
接下来就是如何使用mybatis进行模糊查询,也就是like语句的使用,并且不留SQL注入隐患
1 User getuserbylike (Map<String,Object> map) ;
1 2 3 <select id ="getuserbylike" parameterType ="Map" resultType ="com.kino.pojo.User" > select * from user where name like concat("%",#{name},"%") </select >
1 2 3 4 5 6 7 8 9 10 @Test public void selectbylike () { SqlSession sqlSession=MybatisUtil.getSqlsession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String,Object> hashMap=new HashMap <>(); hashMap.put("name" ,"B" ); User getuserbylike = mapper.getuserbylike(hashMap); System.out.println(getuserbylike); sqlSession.close(); }
![image.png](https://cdn.nlark.com/yuque/0/2023/png/32634994/1672928237047-9dd461d5-67b8-417c-88db-fdcb1bfe39e1.png#averageHue=%238a7861&clientId=uf2c195bd-4fd7-4&from=paste&height=101&id=uf3a90cc7&name=image.png&originHeight=126&originWidth=565&originalType=binary&ratio=1&rotation=0&showTitle=false&size=13708&status=done&style=none&taskId=u3b110d33-fff4-4127-9813-a409c5f5a45&title=&width=452)
注意XML中我用了concat,这样可以从一定程度避免sql注入
配置优化——属性 mybatis核心配置文件如上,我们environment和mappers我们都用过了,这里介绍一下属性properties 首先先回顾一下environments:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.cj.jdbc.Driver" > </property > <property name ="url" value ="jdbc:mysql://localhost:3306/mybatis?useSSL=true& useUnicode=true& characterEncoding=UTF-8" > </property > <property name ="username" value ="root" > </property > <property name ="password" value ="jiayou357753" > </property > </dataSource > </environment > <environment id ="test" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="com.mysql.cj.jdbc.Driver" > </property > <property name ="url" value ="jdbc:mysql://localhost:3306/mybatis?useSSL=true& useUnicode=true& characterEncoding=UTF-8" > </property > <property name ="username" value ="root" > </property > <property name ="password" value ="jiayou357753" > </property > </dataSource > </environment > </environments >
上面部分核心配置文件中,有2个environment,我们假如想要切换,只需修改default
标签为对应的id即可
transactionManager
标签也就是事务管理器,有JDBC和MANAGED两种方式,但是MANAGED我们已经不再用了
dataSource
标签表示数据源,如dbcp、c3p0、druid、JNDI
在mybatis中自带3种内置数据源类型JNDI,UNPOOLED,POOLED
,POOL也就是池的意思,代表能否复用的意思(用完了换个进程继续用),UNPOOLED也就是没有池的概念,因此性能要求不高mybatis可以配置成适应多种环境,但是SqlsessionFactory只能用一种 mybatis的默认事务处理器是JDBC,连接池是POOLED
properties属性 可以用来引入.properties
配置文件,也可以在标签中自己添加属性和数值
1 2 3 4 driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&seUnicode=true&characterEncoding=UTF-8 username=root password=jiayou357753
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?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 resource ="db.properties" > <property name ="useless" value ="useless" /> </properties > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="${driver}" > </property > <property name ="url" value ="${url}" > </property > <property name ="username" value ="${username}" > </property > <property name ="password" value ="${password}" > </property > </dataSource > </environment > </environments > <mappers > <mapper resource ="com/kino/dao/UserMapper.xml" /> </mappers > </configuration >
${}
:和#{}
一样也是一种占位符
别名配置优化 方案一 在mybatis-config.xml有个tag叫做<typeAliases>
,它用来对我们的类设置别名,比如我们再Usermapper.xml中,设置resultType每次都是com.kino.pojo.User
每次都要写这么长就很繁琐,因此可以设置别名:
1 2 3 <typeAliases > <typeAlias type ="com.kino.pojo.User" alias ="User" /> </typeAliases >
mybatis核心配置文件内,这些标签有顺序的,这个需要写在properties标签下,这里需要注意 标签顺序如上 配置过后就可以把UserMapper.Xml的内容翻一番了
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 28 <?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.kino.dao.UserMapper" > <select id ="getuserlist" resultType ="com.kino.pojo.User" > select * from user </select > <select id ="getuserbyid" resultType ="User" parameterType ="int" > select * from user where id=#{id} </select > <insert id ="adduser" parameterType ="User" > insert into mybatis.user(id,name,pwd) values(#{id},#{name},#{pwd}); </insert > <delete id ="deluser" parameterType ="int" > delete from user where id=#{id} </delete > <update id ="cguser" parameterType ="User" > update user set name=#{name},pwd=#{pwd} where id=#{id} </update > <insert id ="mapadduser" parameterType ="Map" > insert into user(id,name) values(#{id},#{name}) </insert > <select id ="getuserbylike" parameterType ="Map" resultType ="User" > select * from user where name like concat("%",#{name},"%") </select > </mapper >
运行test类看看结果是否正常: 结果正常说明配置生效
方案二 还有一种写法
1 2 3 <typeAliases > <package name ="com.kino.pojo" /> </typeAliases >
这样的写法默认会讲com.kino.pojo下的类别名设置为类名的小写形式,如User的别名就是user 当然我们可以通过注解自定义别名: 测试一下是否正常运行 运行正常
这两种的适用的场合也就是你需要别名的类是否很多,如果很多的话就用方案二的package,很少就用方案一吧,我个人是倾向于方案二的
映射器配置 映射器已经见得多了,就是mybatis核心配置文件中注册我们mapper的标签 它有如下三种写法:
1 2 3 4 <mappers > <mapper resource ="com/kino/dao/UserMapper.xml" /> </mappers >
1 2 3 4 <mappers > <mapper class ="com.kino.dao.UserMapper" /> </mappers >
1 2 3 4 <mappers > <mapper url ="file:///var/mappers/AuthorMapper.xml" /> </mappers >
1 2 3 4 <mappers > <package name ="org.mybatis.builder" /> </mappers >
以上四种用法结合实际情况去使用
作用域(Scope)和生命周期 SqlSessionFactoryBuilder 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。
SqlSessionFactory SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。 (就如我们这次项目使用的就是单例模式)
SqlSession 每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式:
1 2 3 try (SqlSession session = sqlSessionFactory.openSession()) { }
可以将SqlSessionFactory理解为一个线程池,然后SqlSession用来连接线程池,因此当SqlSession结束了事务后,要关闭SqlSession避免占用
ResultMap结果集映射 我们如何利用ResultMap结果映射集去解决pojo中类属性名称和数据库中字段名称不一致的问题呢,针对这个问题其实有两种解法,分别从数据库和mybatis方向去解决
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package com.kino.pojo;import org.apache.ibatis.type.Alias;@Alias("User") public class User { private int id; private String name; private String password; @Override public String toString () { return "User{" + "id=" + id + ", name='" + name + '\'' + ", password='" + password + '\'' + '}' ; } public void setId (int id) { this .id = id; } public void setName (String name) { this .name = name; } public void setPassword (String password) { this .password = password; } public int getId () { return id; } public String getName () { return name; } public String getPassword () { return password; } public User () { } }
注意这里我用了无参构造方法啊,这里的坑后面会讲 这样查出来的password为空
方案1——使用as别名 将select * from user
改为select id,name,pwd as password from user
即可
方案2(推荐)——使用ResultMap映射 这是官方文档的用法,但是看官方文档总是会有种不说人话的感觉 我们将我们的UserMapper文件改为:
1 2 3 4 5 6 7 <resultMap id ="Anything" type ="User" > <result property ="password" column ="pwd" /> </resultMap > <select id ="getuserbyid" resultMap ="Anything" parameterType ="int" > select * from user where id=#{id} </select >
将结果设为resultMap,名称自定义,但是要与上面的resultMap标签的id属性对应,这就是设置一个映射关系,同样的结果也能显示出来
填坑 回来填坑,为什么要用无参的构造方法呢,因为经过我的测试,假如你的构造器是有参构造器,不管你字段名和属性对不对应结果都会返回结果 这边猜测是mybatis处理结果时,会优先使用有参构造函数去返回结果的User类,这就是一个自动对应 假如用无参构造方法的话,就只能更改属性了,因此就没有对应关系 纯属个人猜测
日志工厂 在mybatis中由于简化jdbc事务,因此不能直接使用out去输出运行的Sql语句,由此日志工厂诞生了: mybatis中默认不开启日志事务,因此需要手动添加配置
默认日志 1 2 3 4 <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> </settings >
配置好xml文件后在测试类中运行发现多出了日志文件
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter. Class not found: org.jboss.vfs.VFS JBoss 6 VFS API is not available in this environment. Class not found: org.jboss.vfs.VirtualFile VFS implementation org.apache.ibatis.io.JBoss6VFS is not valid in this environment. Using VFS adapter org.apache.ibatis.io.DefaultVFS Find JAR URL: file:/E:/CTF%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0/Mybatis/Mybatis/mabtis-01/target/classes/com/kino/pojo Not a JAR: file:/E:/CTF%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0/Mybatis/Mybatis/mabtis-01/target/classes/com/kino/pojo Reader entry: User.class Listing file:/E:/CTF%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0/Mybatis/Mybatis/mabtis-01/target/classes/com/kino/pojo Find JAR URL: file:/E:/CTF%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0/Mybatis/Mybatis/mabtis-01/target/classes/com/kino/pojo/User.class Not a JAR: file:/E:/CTF%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0/Mybatis/Mybatis/mabtis-01/target/classes/com/kino/pojo/User.class Reader entry: ���� 4 @ - Checking to see if class com.kino.pojo.User matches criteria [is assignable to Object] PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. PooledDataSource forcefully closed/removed all connections. Opening JDBC Connection Created connection 1380806038. Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@524d6d96] ==> Preparing: select * from user ==> Parameters: <== Columns: id, name, pwd <== Row: 1, Kino!, asdasdasd <== Row: 2, boogipop, admin <== Row: 3, Boogipop2, 2662501 <== Row: 4, Boogipop4, 2662501 <== Row: 4, Boogipop4, 2662501 <== Row: 4, Boogipop4, 2662501 <== Total: 6 User{id=1, name='Kino!', pwd='asdasdasd'} User{id=2, name='boogipop', pwd='admin'} User{id=3, name='Boogipop2', pwd='2662501'} User{id=4, name='Boogipop4', pwd='2662501'} User{id=4, name='Boogipop4', pwd='2662501'} User{id=4, name='Boogipop4', pwd='2662501'} Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@524d6d96] Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@524d6d96] Returned connection 1380806038 to pool. Process finished with exit code 0
我们的SQL执行语句已经在上面给显示出来了
LOG4J2 https://www.jianshu.com/p/c6c543e4975e 配置文件之类的参考如上: LOG4J漏洞百出,现在用的都是2 先安装Maven依赖:
1 2 3 4 5 6 7 8 9 10 <dependency > <groupId > org.apache.logging.log4j</groupId > <artifactId > log4j-slf4j-impl</artifactId > <version > 2.19.0</version > </dependency > <dependency > <groupId > org.apache.logging.log4j</groupId > <artifactId > log4j-core</artifactId > <version > 2.19.0</version > </dependency >
之后再mybatis核心配置文件中的settings设置一下logImpl的种类为LOG4J2:
1 2 3 <settings > <setting name ="logImpl" value ="LOG4J2" /> </settings >
之后只需要设置一下log4j2的xml配置文件即可:
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 28 29 30 31 32 33 34 35 36 <?xml version="1.0" encoding="UTF-8" ?> <Configuration status ="TRACE" > <Appenders > <Console name ="Console" target ="SYSTEM_OUT" > <PatternLayout pattern ="%d{HH:mm:ss} [%t] %-5level %logger{36} - %msg%n" /> "/> </Console > <File name ="MyFile" fileName ="./logs/info.log" append ="true" > <PatternLayout > <pattern > %d{HH:mm:ss} [%t] %-5level %logger{36} - %msg%n</pattern > </PatternLayout > </File > </Appenders > <Loggers > <logger name ="com.kino.dao.UserMapper" level ="TRACE" additivity ="false" > <AppenderRef ref ="Console" /> <AppenderRef ref ="MyFile" /> </logger > <Root level ="info" > <AppenderRef ref ="Console" /> <AppenderRef ref ="MyFile" /> </Root > </Loggers > </Configuration >
这样日志文件就会在控制台和文件中输出
然后同时我们也可以在我们的测试类中使用LOG4J2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 static Logger logger=LogManager.getLogger(); @Test public void test () { SqlSession sqlsession = MybatisUtil.getSqlsession(); UserMapper mapper = sqlsession.getMapper(UserMapper.class); logger.info("=====info信息开始=====" ); List<User> getuserlist = mapper.getuserlist(); for (User user : getuserlist) { System.out.println(user); } sqlsession.close(); }
用法大概就这样拉QWQ
Limit实现分页 使用limit 就普通SQL的limit语法
使用RowBounds 大概就如上的用法,通过代码层面来实现分页,其实没啥东西
使用注解进行开发 上述我们进行的操作都是通过接口和xml文件进行的,现在来说一下如何直接利用注解来执行SQL语句:
1 2 3 4 5 6 7 8 9 10 11 12 13 package com.boogipop.dao;import com.boogipop.pojo.User;import org.apache.ibatis.annotations.Select;import java.util.List;public interface UserMapper { @Select("select * from user") List<User> getuserlist () ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 package com.boogipop.dao;import com.boogipop.pojo.User;import org.apache.ibatis.annotations.Select;import java.util.List;public interface UserMapper { @Select("select * from user") List<User> getuserlist () ; }
1 2 3 <mappers> <mapper class="com.boogipop.dao.UserMapper" /> </mappers>
核心配置文件中关于mappers的映射就要改为class了 结果是能正常输出,但是password为null,这是因为字段和属性名称不对应,所以假如用注解去执行SQL的时候就切记一定要对应起来,否则就null了 下个断点调试其实可以发现mapper是后续是通过反射获取的
增删改查 我们同样也可以通过注解来实现增删改查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.boogipop.dao;import com.boogipop.pojo.User;import org.apache.ibatis.annotations.*;import java.util.HashSet;import java.util.List;public interface UserMapper { @Select("select * from user") List<User> getuserlist () ; @Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password})") Boolean adduser (User user) ; @Update("update user set name=#{name},pwd=#{password} where id=#{id}") Boolean updateuser (User user) ; @Delete("delete from user where id=#{id}") Boolean deleteuser (@Param("id") int id) ; @Select("select * from user where name=#{name}") HashSet<User> getuserbyname (@Param("name") String name) ; }
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 package com.boogipop.dao;import com.boogipop.pojo.User;import com.boogipop.utils.MybatisUtil;import org.apache.ibatis.session.SqlSession;import org.junit.Test;import java.util.HashSet;import java.util.List;public class UserDaotest { @Test public void select () { SqlSession sqlsession = MybatisUtil.getSqlsession(); UserMapper mapper = sqlsession.getMapper(UserMapper.class); List<User> getuserlist = mapper.getuserlist(); for (User user : getuserlist) { System.out.println(user); } sqlsession.close(); } @Test public void adduser () { SqlSession sqlsession = MybatisUtil.getSqlsession(); UserMapper mapper = sqlsession.getMapper(UserMapper.class); User user=new User (5 ,"ass" ,"123" ); Boolean adduser = mapper.adduser(user); if (adduser){ System.out.println("Add successfully!" ); } sqlsession.close(); } @Test public void updateuse () { SqlSession sqlSession=MybatisUtil.getSqlsession(); UserMapper mapper=sqlSession.getMapper(UserMapper.class); User user=new User (3 ,"Jack" ,"sada123sdd2!" ); Boolean updateuser = mapper.updateuser(user); if (updateuser){ System.out.println("update successfully" ); } sqlSession.close(); } @Test public void deleteuser () { SqlSession sqlSession=MybatisUtil.getSqlsession(); UserMapper mapper=sqlSession.getMapper(UserMapper.class); Boolean deleteuser = mapper.deleteuser(4 ); if (deleteuser){ System.out.println("delete successfully" ); } sqlSession.close(); } @Test public void getbyid () { SqlSession sqlSession=MybatisUtil.getSqlsession(); UserMapper userMapper=sqlSession.getMapper(UserMapper.class); HashSet<User> boogipop = userMapper.getuserbyname("boogipop" ); for (User user : boogipop) { System.out.println(user); } sqlSession.close(); } }
当参数为基本类型时需要用param去强调,是引用类型的时候就免了,另外注意param参数对应的问题 然后这里大家可能发现我没提交事务,因为我改了一下工具类: 我传了一个ture进去就代表会自动提交,默认为false
mybatis执行流程 这个我们已经有了一个总体的认知,mybatis其实就是对底层jdbc的一个包装 不细讲 SqlSessionFactoryBuilder->inputStream->得到xml配置->sqlSessionFactory->transaction事务管理->excutor执行器->得到Sqlsession
Lombok简化 啥是lombok呢,我们创建一个类可以用alt+insert去添加一些常用方法 而lombok直接就更加简化了这些步骤,首先在settings里的plugins中安装lombok插件,然后再导入maven依赖:
1 2 3 4 5 6 7 <dependencies > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.18.24</version > </dependency > </dependencies >
包含所有参数的构造方法
无参构造方法
这些注解会自动帮你添加这些方法,就挺方便
复杂查询模式环境搭建 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 CREATE TABLE `teacher` ( `id` INT(10) NOT NULL, `name` VARCHAR(30) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8 INSERT INTO teacher(`id`, `name`) VALUES (1, 'Boogipop'); CREATE TABLE `student` ( `id` INT(10) NOT NULL, `name` VARCHAR(30) DEFAULT NULL, `tid` INT(10) DEFAULT NULL, PRIMARY KEY (`id`), CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8 INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', 'Kino', '1'); INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', 'Jack', '1'); INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', 'Benk', '1'); INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', 'Siri', '1'); INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', 'Benk', '1');
首先先在本地SQL创建一下表,这里其实对KEY这个概念有点生疏,PRIMARY KEY
表示主键,FOREIGN KEY
表示外键,用来把本表字段和其他表字段做一个约束:https://www.jianshu.com/p/010106e61cc6 在这里对student表创建了主键id,不准有重复的列、不能有NULL值,每个表只有一个主键 这样表就构造好了,接下来要做的是在Mybatis中去处理这种关联关系,在这里一个老师对应多个学生 先新建一个mybatis子项目,然后把pojo和dao啥的翻一番:
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 28 29 <?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 resource ="db.properties" > <property name ="useless" value ="useless" /> </properties > <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> </settings > <typeAliases > <package name ="com.mybatis3.pojo" /> </typeAliases > <environments default ="development" > <environment id ="development" > <transactionManager type ="JDBC" > </transactionManager > <dataSource type ="POOLED" > <property name ="driver" value ="${driver}" > </property > <property name ="url" value ="${url}" > </property > <property name ="username" value ="${username}" > </property > <property name ="password" value ="${password}" > </property > </dataSource > </environment > </environments > <mappers > <mapper resource ="StudentMapper.xml" /> </mappers > </configuration >
1 2 3 4 5 6 7 8 9 <?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.mybatis3.dao.StudentMapper" > <select id ="getstudentlist" resultType ="Student" > select * from student </select > </mapper >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.mybatis3.pojo;import lombok.Data;import org.apache.ibatis.type.Alias;@Data @Alias("Student") public class Student { private int id; private String name; private int tid; private Teacher teacher; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import com.mybatis3.dao.StudentMapper;import com.mybatis3.pojo.Student;import com.mybatis3.utils.MybatisUtil;import org.apache.ibatis.session.SqlSession;import org.junit.Test;import java.util.List;public class Excute { @Test public void getstudent () { SqlSession sqlSession= MybatisUtil.getSqlsession(); StudentMapper mapper=sqlSession.getMapper(StudentMapper.class); List<Student> getstudentlist = mapper.getstudentlist(); for (Student student : getstudentlist) { System.out.println(student); } sqlSession.close(); } }
1 2 3 4 5 6 7 8 9 10 package com.mybatis3.dao;import com.mybatis3.pojo.Student;import java.util.List;public interface StudentMapper { List<Student> getstudentlist () ; }
这样就可以正常得到我们的测试结果: 因为返回值里没teacher所以为false 然后由于我们设置了主键,所以现在就有个非常有意思是的现象: 主键不能重复 而且我们添加数据的时候会自动帮我们加上id: 挺方便的,所以在创建SQL的时候记得加个主键约束
多对一处理 现在我们要完成一个需求,搜索学生的时候,顺便把和tid绑定的teacher的信息一起输出出来。
查询进行嵌套 1 List<Student> getteacherlist ();
1 2 3 4 5 6 <select id ="selectall" resultMap ="all" > select * from student </select > <resultMap id ="all" type ="Student" > <association property ="teacher" column ="tid" javaType ="Teacher" select ="getteacherlist" /> </resultMap >
1 2 3 4 5 6 7 8 9 public void selectall () { SqlSession sqlSession= MybatisUtil.getSqlsession(); StudentMapper mapper=sqlSession.getMapper(StudentMapper.class); List<Student> selectall = mapper.selectall(); for (Student student : selectall) { System.out.println(student); } sqlSession.close(); }
可以看到teacher也跟着被输出了,这里的意思其实是tid和getteacherlist接口绑定了
结果进行嵌套 1 2 3 4 5 6 7 8 9 10 11 <select id ="selectall2" resultMap ="all2" > select s.id sid,s.name sname,s.tid tid,t.name tname from student s join teacher t on s.tid=t.id </select > <resultMap id ="all2" type ="Student" > <result property ="tid" column ="tid" /> <result property ="name" column ="sname" /> <result column ="sid" property ="id" /> <association property ="teacher" javaType ="Teacher" > <result column ="tname" property ="name" /> </association > </resultMap >
1 2 3 4 5 6 7 8 9 public void selectall2 () { SqlSession sqlSession= MybatisUtil.getSqlsession(); StudentMapper mapper=sqlSession.getMapper(StudentMapper.class); List<Student> selectall = mapper.selectall2(); for (Student student : selectall) { System.out.println(student); } sqlSession.close(); }
teacher中的id为0是因为我们没有选择t.id
一对多处理 昨天讲了多对一,今天将一对多,多对一使用了association
标签,而一对多使用collenction
标签,都是对应起来的 在实验之前先建一个新的mybatis项目
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.mybatis3.pojo;import lombok.Data;import org.apache.ibatis.type.Alias;import java.util.List;@Data @Alias("Teacher") public class Teacher { private int id; private String name; List<Student> students; }
1 2 3 4 5 6 7 8 9 10 11 12 13 package com.mybatis3.pojo;import lombok.Data;import org.apache.ibatis.type.Alias;@Data @Alias("Student") public class Student { private int id; private String name; private int tid; }
这次两个pojo类反过来了,xml文件肯定也要去修改一下的,这次是查询老师的信息顺便把所有关联学生的信息带出来
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 28 29 30 31 32 33 34 35 36 <?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.mybatis3.dao.StudentMapper" > <select id ="getstudentlist" resultType ="Student" > select * from student where tid=#{tid} </select > <insert id ="add" parameterType ="Student" > insert into student(id,name) values (#{id},#{name}) </insert > <select id ="getteacherlist" resultType ="Teacher" > select * from teacher </select > <select id ="selectall" resultMap ="all" > select * from teacher </select > <resultMap id ="all" type ="Teacher" > <result property ="id" column ="id" /> <collection property ="students" ofType ="Student" column ="id" select ="getstudentlist" > </collection > </resultMap > <select id ="selectall2" resultMap ="all2" > select * from teacher where id=#{id} </select > <resultMap id ="all2" type ="Teacher" > <result column ="id" property ="id" /> <result column ="name" property ="name" /> <collection property ="students" ofType ="Student" > <result column ="id" property ="id" /> <result column ="name" property ="name" /> <result column ="tid" property ="tid" /> </collection > </resultMap > </mapper >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.mybatis3.dao;import com.mybatis3.pojo.Student;import com.mybatis3.pojo.Teacher;import java.util.List;public interface StudentMapper { List<Student> getstudentlist (int tid) ; Boolean add (Student student) ; List<Teacher> getteacherlist () ; List<Teacher> selectall () ; List<Teacher> selectall2 (int id) ; }
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import com.mybatis3.dao.StudentMapper;import com.mybatis3.pojo.Student;import com.mybatis3.pojo.Teacher;import com.mybatis3.utils.MybatisUtil;import org.apache.ibatis.session.SqlSession;import org.junit.Test;import java.util.List;public class Excute { @Test public void getstudent () { SqlSession sqlSession= MybatisUtil.getSqlsession(); StudentMapper mapper=sqlSession.getMapper(StudentMapper.class); List<Student> getstudentlist = mapper.getstudentlist(1 ); for (Student student : getstudentlist) { System.out.println(student); } sqlSession.close(); } @Test public void getteacherlist () { SqlSession sqlSession= MybatisUtil.getSqlsession(); StudentMapper mapper=sqlSession.getMapper(StudentMapper.class); List<Teacher> getteacherlist = mapper.getteacherlist(); for (Teacher teacher : getteacherlist) { System.out.println(teacher); } sqlSession.close(); } @Test public void selectall () { SqlSession sqlSession= MybatisUtil.getSqlsession(); StudentMapper mapper=sqlSession.getMapper(StudentMapper.class); List<Teacher> selectall = mapper.selectall(); for (Teacher student : selectall) { System.out.println(student); } sqlSession.close(); } @Test public void selectall2 () { SqlSession sqlSession= MybatisUtil.getSqlsession(); StudentMapper mapper=sqlSession.getMapper(StudentMapper.class); List<Teacher> selectall = mapper.selectall2(1 ); for (Teacher student : selectall) { System.out.println(student); } sqlSession.close(); } }
这里要注意一个小坑,就是我们这样映射查询的时候pojo类中必须要有无参构造方法:https://blog.csdn.net/weixin_50236329/article/details/112312423
动态SQL环境搭建 1 2 3 4 5 6 7 CREATE TABLE `blog`( `id` VARCHAR(50) NOT NULL COMMENT '博客id', `title` VARCHAR(100) NOT NULL COMMENT '博客标题', `author` VARCHAR(30) NOT NULL COMMENT '博客作者', `create_time` DATETIME NOT NULL COMMENT '创建时间', `views` INT(30) NOT NULL COMMENT '浏览量' )ENGINE=INNODB DEFAULT CHARSET=utf8
先把这个SQL搭建了,然后创建一个mybatis子项目搭建一个环境
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.mybatis5.pojo;import lombok.Data;import org.apache.ibatis.type.Alias;import java.util.Date;@Data @Alias("Blog") public class Blog { private String id; private String title; private String author; private Date create_time; private int views; }
1 2 3 4 5 6 7 8 package com.mybatis5.dao;import com.mybatis5.pojo.Blog;public interface BlogMapper {Boolean AddBlog (Blog blog) ; }
1 2 3 4 5 6 7 8 <?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.mybatis5.dao.BlogMapper" > <insert id ="AddBlog" parameterType ="Blog" > insert into blog(id,title,author,create_time,views) values (#{id},#{title},#{author},#{create_time},#{views}) </insert > </mapper >
1 2 3 4 5 6 7 8 9 10 11 package com.mybatis5.utils;import java.util.UUID;public class UuidUtils { public static String getId () { String uuid = UUID.randomUUID().toString().replace("-" , "" ); return uuid; } }
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 28 29 30 import com.mybatis5.dao.BlogMapper;import com.mybatis5.pojo.Blog;import com.mybatis5.utils.MybatisUtil;import com.mybatis5.utils.UuidUtils;import org.apache.ibatis.session.SqlSession;import org.junit.Test;import java.util.Date;public class Excute { @Test public void addblog () { Blog blog=new Blog (); String uuid= UuidUtils.getId(); Date time=new Date (); blog.setId(uuid); blog.setCreate_time(time); blog.setAuthor("Nano" ); blog.setTitle("不知道是什么" ); blog.setViews(100 ); SqlSession sqlSession= MybatisUtil.getSqlsession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Boolean aBoolean = mapper.AddBlog(blog); if (aBoolean){ System.out.println("add successfully" ); } sqlSession.close(); } }
这样先添加个几组数据: 在这我们多加了一个util,用于获取uuid的,在正规场合id不可能是1,2,3
动态SQL IF标签以及常用标签 https://mybatis.org/mybatis-3/zh/dynamic-sql.html 我觉得这部分跟着官方文档走就知道了
IF标签 这里的测试类就是上述构造出来的,这里就只放Xml文件中的语句了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?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.mybatis5.dao.BlogMapper" > <insert id ="AddBlog" parameterType ="Blog" > insert into blog(id,title,author,create_time,views) values (#{id},#{title},#{author},#{create_time},#{views}) </insert > <select id ="selectall" resultType ="Blog" parameterType ="Map" > select * from blog where <if test ="author != null" > author=#{author} </if > <if test ="title != null" > and title=#{title} </if > </select > </mapper >
1 2 3 4 5 6 7 8 9 10 11 12 public void selectall () { SqlSession sqlSession= MybatisUtil.getSqlsession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map<String,String> map=new HashMap <>(); map.put("title" ,"不吉波普不笑" ); map.put("author" ,"Boogipop" ); List<Blog> selectall = mapper.selectall(map); for (Blog blog : selectall) { System.out.println(blog); } sqlSession.close(); }
if如同字面意思假如author或者title形参不为空就拼接(这里的author和title是对应#{}的) 但是这样就有个问题,假如我author为空title不为空 sql就为select * from blog where and title=?
,这里就要引入Where标签
WHERE标签 1 2 3 4 5 6 7 8 9 10 <select id ="selectall" resultType ="Blog" parameterType ="Map" > select * from blog <where > <if test ="author != null" > and author=#{author} </if > <if test ="title != null" > and title=#{title} </if > </where > </select >
1 2 3 4 5 6 7 8 9 10 11 12 13 @Test public void selectall () { SqlSession sqlSession= MybatisUtil.getSqlsession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map<String,String> map=new HashMap <>(); map.put("author" ,"Nano" ); List<Blog> selectall = mapper.selectall(map); for (Blog blog : selectall) { System.out.println(blog); } sqlSession.close(); }
使用where标签会自动为你剔除前置的第一个and ,多了不行,后置了也不行
choose、when、otherwise 这三个就是if,else if,else
,感觉没什么区别,也是以一个例子说明
1 2 3 4 5 6 7 8 9 10 11 12 13 <select id ="chooseall" resultType ="Blog" parameterType ="Map" > select * from blog <where > <choose > <when test ="author !=null" > and author=#{author} </when > <when test ="title !=null" > and title=#{title} </when > </choose > </where > </select >
1 2 3 4 5 6 7 8 9 10 11 12 13 @Test public void chooseall () { SqlSession sqlSession= MybatisUtil.getSqlsession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map<String,String> map=new HashMap <>(); List<Blog> selectall = mapper.chooseall(map); for (Blog blog : selectall) { System.out.println(blog); } sqlSession.close(); }
由于when都不满足就默认全选了
1 2 3 4 5 6 7 8 9 10 11 12 13 @Test public void chooseall () { SqlSession sqlSession= MybatisUtil.getSqlsession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map<String,String> map=new HashMap <>(); map.put("title" ,"不吉波普不笑" ); map.put("author" ,"Nano" ); List<Blog> selectall = mapper.chooseall(map); for (Blog blog : selectall) { System.out.println(blog); } sqlSession.close(); }
由于author标签在前,所以优先
trim、set where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。 如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
1 2 3 <trim prefix ="WHERE" prefixOverrides ="AND |OR " > ... </trim >
然后再来看看set,set就是update的时候用的标签,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <update id ="updateblog" parameterType ="Map" > update blog <set > <if test ="title!=null" > title=#{title}, </if > <if test ="author!=null" > author=#{author}, </if > <if test ="views!=null" > views=#{views} </if > <where > <choose > <when test ="id!=null" > id=#{id} </when > <otherwise > id="1" </otherwise > </choose > </where > </set > </update >
究极无敌的一个update标签,哈哈哈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public void updateblog () { SqlSession sqlSession= MybatisUtil.getSqlsession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map<String,Object> map=new HashMap <>(); map.put("author" ,"Boogipop" ); map.put("views" ,100000 ); map.put("id" ,"53bbe5be5a174532bcdb1f9951eb0664" ); Boolean updateblog = mapper.updateblog(map); if (updateblog){ System.out.println("update successfully" ); } sqlSession.close(); }
这个标签就指定的很智能了,如果不指定id就更改不到信息
include标签 动态SQL foreach标签 foreach的用法其实很简单,以一个例子来说,我们要取数据前三条select * from user where id in(1,2,3)
在不用分页的情况下怎么做到呢?
1 List<Blog> foreachselect (Map map) ;
1 2 3 4 5 6 <select id ="foreachselect" resultType ="Blog" parameterType ="Map" > select * from blog where author in <foreach collection ="strings" index ="index" item ="str" open ="(" separator ="," close =")" > #{str} </foreach > </select >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public void foreach () { SqlSession sqlSession= MybatisUtil.getSqlsession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map<String,Object> map=new HashMap <>(); List<String> strings = new ArrayList <>(); strings.add("Kino" ); strings.add("Nano" ); map.put("strings" ,strings); List<Blog> foreachselect = mapper.foreachselect(map); for (Blog blog : foreachselect) { System.out.println(blog); } sqlSession.close(); }
就这么简单
缓存简介 也就是请求相同资源时假如不做缓存会让性能降低,缓存就是把结果储存,再请求的时候不需要反复执行SQL,只需要执行一次即可 一级缓存是默认开启的: 也就是在你一个sqlsession中,如果你反复执行一条同样的语句,语句的结果就会进入sqlsession的缓存,这样就只会执行一次sql语句,当sqlsession关闭时,缓存也没了
二级缓存 MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。 默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:<cache/>
基本上就是这样。这个简单语句的效果如下:
映射语句文件中的所有 select 语句的结果将会被缓存。
映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
缓存不会定时进行刷新(也就是说,没有刷新间隔)。
缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
提示 缓存只作用于 cache 标签所在的映射文件中的语句。如果你混合使用 Java API 和 XML 映射文件,在共用接口中的语句将不会被默认缓存。你需要使用 @CacheNamespaceRef 注解指定缓存作用域。 这些属性可以通过 cache 元素的属性来修改。比如: 这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。 可用的清除策略有:
LRU – 最近最少使用:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
默认的清除策略是 LRU。 flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。 size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。 readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。 提示 二级缓存是事务性的。这意味着,当 SqlSession 完成并提交时,或是完成并回滚,但没有执行 flushCache=true 的 insert/delete/update 语句时,缓存会获得更新
二级缓存是作用在UserMapper.xml上的,我们使用前需要开启一下settings中的缓存选项: 默认是开的,但是为了让别人知道开了再写一遍: 然后在usermapeer.xml中开启缓存即可
小结 完结啦!mybatis挺方便的,suki