2022-9-12-Mybatis基础
一、认识Mybatis
1.1 什么是mybatis?
- 一款优秀的持久层框架
- 支持定制化sql,存储过程以及高级映射
- Mybatis避免了几乎所有的JDBC代码和手动测试参数以及获取结果集
- 可以使用简单的xml或注解来配置和映射原生类型,接口和java的pojo
如何获得mybatis?
-
maven仓库的依赖
-
github
1.2 持久层
数据持久化
持久化:将程序的数据在持久状态和瞬时状态转化的过程
为什么需要持久化:
- 有一些对象不能丢掉
- 内存少,贵
为什么需要mybatis
- 传统的jdbc代码太复杂
- 帮助将数据存在数据库中
1.3 第一个Mybatis程序
先搭建一个数据库:
CREATE DATABASE `mybatis`;
USE `mybatis`;
CREATE TABLE `user`(`id` INT(20) NOT NULL PRIMARY KEY,
`name` VARCHAR(30) DEFAULT NULL,
`pwd` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(id,`name`,`pwd`) VALUES(1,'bo','123456'),(2,'只因','123456'),(3,'ikun','123809');
新建maven项目,导入依赖,删除src,建立子工程
<!--导入依赖-->
<!--mysql-->
<!--mybatis-->
<!--Junit-->
建立好子工程后:
- 编写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核心配置文件-->
<configuration>
<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>
</configuration>
配置文件中的一些参数,根据我们之前学的jdbc更改即可,改完后是这样:
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF8&useUnicode=true&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
然后是使用mybatis的第一步,我们首先要写一个util工具类,类似于jdbc的工具类:
//获取sqlSessionFactory对象
static {
try {
String resource="mybatis-config.xml";
//获取resource
InputStream inputStream = Resources.getResourceAsStream(resource);
//加载resource的流(build)
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
第一段静态代码块类似于jdbcutil注册driver,只需要执行一次就拿到sqlSessionFactory对象即可
既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
但现在有一个问题,我们拿到的这个sqlSessionFactory无法在静态代码块外调用,我们需要提升作用域:
private static SqlSessionFactory sqlSessionFactory;
//获取sqlSessionFactory对象
static {
try {
String resource="mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//有了sqlSessionFactory ,我们就可以从中获得sqlsession的实例了
//工具类写成方法写成静态方便类名调用
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
在Dao层写一个普通的userdao接口:
public interface UserDao {
List<User> getUserList();
}
然后在dao层需要一个配置文件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">
<!--namespace=绑定一个对应的DAO/Mapper接口-->
<mapper namespace="com.bo.dao.UserDao">
<!--这里填入具体的对某个表的操作:select,delete,insert等-->
</mapper>
比如我们要进行一个查询操作查询user表,我们就在mapper里面写:
<select id="getUserList" resultType="com.bo.pojo.User">
select * from mybatis.user
</select>
即可,就不需要再去接口的实现类中重写getUserList方法,id=要执行sql的方法名
我们执行查询要返回一个结果集,resultType=”com.bo.pojo.User”即是返回的结果的类型
总结:接口实现类由原来的UserDaoimp变成了UserMapper.xml
1.3.1 测试
@Test
public void test(){
//获取SqlSession对象
SqlSession sqlSession = MybatisUtil.getSqlSession();
//执行sql、
//方式一getMapper
UserDao userDao = sqlSession.getMapper(UserDao.class);
for (User user : userDao.getUserList()) {
System.out.println(user);
}
//关闭资源
sqlSession.close();
1.3.1 *测试报错集
第一次测试报错:
org.apache.ibatis.binding.BindingException: Type interface com.bo.dao.UserDao is not known to the MapperRegistry.
我们的核心配置文件没有注册userdao这个mapper,导致找不到,在mybatis-config.xml中注册:
<!--每一个mapper都需要在核心配置文件中注册!-->
<mappers>
<mapper resource="com/bo/dao/UserMapper.xml"/>
</mappers>
第二次测试:
java.lang.ExceptionInInitializerError
### Error building SqlSession.
### Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 18; 1 字节的 UTF-8 序列的字节 1 无效。
该错误是由于一些配置文件如:applicationContext.xml
的编码原因。
在配置文件中引入了<?xml version="1.0" encoding="UTF-8"?>
, 在配置文件可能包含有中文注释,导致在编译后中文注释在配置文件乱码抛异常。
maven项目遇到这种问题,在pom.xml中的properties标签下加上:
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
问题解决。所以最好是建立项目之初就加上这行
至此,测试成功,输出结果:
User{id=1, name='bo', pwd='123456'}
User{id=2, name='只因', pwd='123456'}
User{id=3, name='ikun', pwd='123809'}
1.3.2 总结步骤
- resources下编写mybatis核心配置文件,修改一些东西
- 编写工具类mybatisutil
- 静态代码块:获取sqlSessionFactory对象(工厂)
- getsqlsession方法,得到sqlsession对象
- 对应数据库表中列的pojo类(如user类),Dao接口,绑定接口的配置文件UserMapper.xml并填入要执行的sql语句(相当于实现类重写dao接口的方法)
- 核心配置文件中注册mapper
二、增删改查
原来的Dao接口我们在mybatis中写成mapper接口
我还是使用mybatis(1)中的例子来学习举例
2.1 根据参数查询
首先在usermapper接口中添加方法:
User getUserByID(int id);
然后配置usermapper.xml:
<select id="getUserByID" parameterType="int" resultType="com.bo.pojo.User">
select * from mybatis.user where id= #{id}
</select>
注意,这个时候方法有参数,我们就需要用parameterType=”参数类型”。在sql语句中我们用#来取参数
然后测试:
@Test
public void getUserByIDTest(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
System.out.println(userMapper.getUserByID(1));
sqlSession.close();
}
2.2 insert,update,delete
首先在mapper接口中写方法:
int addUser(User user);
然后配置usermapper.xml:
<insert id="addUser" parameterType="com.bo.pojo.User" >
insert into mybatis.user(id, name, pwd) VALUES (#{id},#{name},#{pwd})
</insert>
注意:
- 对象中的属性,可以直接取出来
- insert不写resultType
然后测试:
@Test
public void addUserTest(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
System.out.println(userMapper.addUser(new User(4,"ikun","654321"))+"个用户已经插入");
//提交事务
sqlSession.commit();
//一定记得close
sqlSession.close();
}
2.2.*关于事务的提交
注意:mybatis如果底层用的是jdbc的话,会默认开启事务,也就是说,mybatis是默认关闭自动提交的
那么,我们在执行了数据库的修改操作后,必须调用sqlSession.commit(),所做的修改才能持久化到硬盘
如何设置mybaitis开启自动提交?
在opensession时传入true即openSession(true);
修改用户
还是一样的流程。
配置usermapper.xml:
<update id="updateUser" parameterType="com.bo.pojo.User">
update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id}
</update>
同样的不写resultType,可以直接将参数中user的属性用#取出来
@Test
public void updateUserTest(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
System.out.println(userMapper.updateUser(new User(4,"kunkun","777777"))+"个用户被修改");
sqlSession.commit();
sqlSession.close();
}
删除用户
同样的流程
配置usermapper.xml:
<delete id="delUser" parameterType="int">
delete from mybatis.user where id=#{id}
</delete>
测试也是一样的。
2.* 总结
增删改查步骤:
- 编写接口
- 在userMapper中配置对应方法,写好sql语句
- 测试
- sqlSession.getMapper
- sqlSession.commit(); 增删改提交事务!
- sqlSession.close();
三、Mybatis使用注解开发
我们可以用在userMapper接口的方法上添加注解的方式实现重写。如:
@Select("select * from user")
List<User> getUserList();
之前我们在mybatis-config核心配置文件中绑定的mapper是usermapper.xml的配置文件,现在我们绑定接口就可以:
<!--每一个mapper都需要在核心配置文件中注册!-->
<mappers>
<mapper class="com.bo.dao.UserMapper"/>
</mappers>
然后测试:
@Test
public void getUserListTest(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
for (User user : userMapper.getUserList()) {
System.out.println(user);
}
sqlSession.close();
}
成功输出
当然这种方式有局限,对于简单的sql语句我们用注解的方式配置即可,但对于复杂的sql语句我们依然需要usermapper.xml的方式
底层核心是反射,动态代理
注解增删改查
3.1 通过参数查询
接口中:
//通过id查询
@Select("select * from user where id=#{id}")
User getUserById(@Param("id")int id);
方法中的用到的参数要用@Param注解,方法上面的注解依然用#获取参数
如果方法存在多个参数,每个参数前面必须加上@Param(“”)
注意:注解上的sql语句取得的参数名对应的是@Param(““)括号里的参数名,二者必须一致,比如这个例子int后面的id可以不叫id,但如果@Param(““)中的参数叫id,#{}中必须是id
测试流程与之前一样。
3.2 insert,update,delete
@Insert("insert into user values(#{id},#{name},#{pwd})")
int addUser(User user);
update:
@Update("update user set name=#{name},pwd=#{pwd} where id=#{id}")
int updateUser(User user);
delete:
@Delete("delete from user where id=#{id}")
int delUser(@Param("id")int id);
测试流程与之前一样。增删改注意提交事务即可。
3.* 总结
- 注解与xml比较少了一个xml文件,sql语句的位置变化
- 注解只适用于简单的sql语句
- 核心配置文件中绑定接口的类而不是mapper文件