Mybatis基础

2022-09-19

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&amp;useUnicode=true&amp;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文件