Mybatis基础系列(一)

一、JDBC缺点分析

(1)数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。如果使用数据库连接池可解决此问题。
(2)Sql语句在代码中硬编码,造成代码不易维护,实际应用中sql变化的可能较大,sql变动需要改变java代码。
(3)使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
(4)对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。

二、Mybatis架构

画了一个图来描述此架构:
这里写图片描述

三、Mybatis入门程序

3.1、根据id查询用户

创建POJO:

package com.long.pojo;

import java.io.Serializable;
import java.util.Date;

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private Integer id;
    private String username;// 用户姓名
    private String sex;// 性别
    private Date birthday;// 生日
    private String address;// 地址


    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", username=" + username + ", sex=" + sex
                + ", birthday=" + birthday + ", address=" + address + "]";
    }
}

创建核心配置文件:
SqlMapConfig.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>
    <!-- 和spring整合后 environments配置将废除    -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url"
                    value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>
    <!-- Mapper的位置  Mapper.xml 写Sql语句的文件的位置 -->
    <mappers>
        <mapper resource="sqlmap/User.xml" />
    </mappers>
</configuration>

sql映射文件User.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">
<!-- 写Sql语句 -->
<!-- 命名空间 -->
<mapper namespace="test">
    <!-- 通过ID查询一个用户 -->
    <select id="findUserById" parameterType="Integer" resultType="com.long.pojo.User">
        select * from user where id = #{v}
    </select>
</mapper>

创建测试文件:

public class MybatisFirstTest {
    @Test
    public void testMybatis() throws Exception {
        //加载核心配置文件
        String resource = "sqlMapConfig.xml";
        InputStream in = Resources.getResourceAsStream(resource);
        //创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        //创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //执行Sql语句 
        User user = sqlSession.selectOne("test.findUserById", 10);

        System.out.println(user);
    }
}

3.2、实现根据用户名模糊查询用户

SQL语句如下:

SELECT * FROM `user` WHERE username LIKE '%王%'

User.xml里面加入这个:

<!-- //根据用户名称模糊查询用户列表
    #{}    select * from user where id = ?    占位符  ? 相当于给变量加了' '
    ${}    select * from user where username like '%五%'  字符串拼接     
-->
    <select id="findUserByUsername" parameterType="String" resultType="com.long.pojo.User">
        elect * from user where username like '%${value}%'
    </select>

测试代码:

@Test
    public void testfindUserByUsername() throws Exception {
        //加载核心配置文件
        String resource = "sqlMapConfig.xml";
        InputStream in = Resources.getResourceAsStream(resource);
        //创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        //创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //执行Sql语句 
        List<User> users = sqlSession.selectList("test.findUserByUsername", "五");
        for (User user2 : users) {
            System.out.println(user2);
        }
    }

3.3、实现添加用户

User.xml:

<!-- 添加用户 -->
    <insert id="insertUser" parameterType="com.pojo.pojo.User">
        <selectKey keyProperty="id" resultType="Integer" order="AFTER">
            select LAST_INSERT_ID()
        </selectKey>
        insert into user (username,birthday,address,sex) 
        values (#{username},#{birthday},#{address},#{sex})
    </insert>

测试程序:

//添加用户
    @Test
    public void testInsertUser() throws Exception {
        //加载核心配置文件
        String resource = "sqlMapConfig.xml";
        InputStream in = Resources.getResourceAsStream(resource);
        //创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        //创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //执行Sql语句 
        User user = new User();
        user.setUsername("龙");
        user.setBirthday(new Date());
        user.setAddress("sadfsafsafs");
        user.setSex("男");
        int i = sqlSession.insert("test.insertUser", user);
        sqlSession.commit();
    }

3.4、mysql自增主键返回

User.xml:

<!-- 保存用户 -->
<insert id="saveUser" parameterType="cn.itcast.mybatis.pojo.User">
    <!-- selectKey 标签实现主键返回 -->
    <!-- keyColumn:主键对应的表中的哪一列 -->
    <!-- keyProperty:主键对应的pojo中的哪一个属性 -->
    <!-- order:设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql -->
    <!-- resultType:设置返回的id的类型 -->
    <selectKey keyColumn="id" keyProperty="id" order="AFTER"
        resultType="int">
        SELECT LAST_INSERT_ID()
    </selectKey>
    INSERT INTO `user`
    (username,birthday,sex,address) VALUES
    (#{username},#{birthday},#{sex},#{address})
</insert>

测试程序:

//添加用户
    @Test
    public void testInsertUser() throws Exception {
        //加载核心配置文件
        String resource = "sqlMapConfig.xml";
        InputStream in = Resources.getResourceAsStream(resource);
        //创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        //创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //执行Sql语句 
        User user = new User();
        user.setUsername("龙");
        user.setBirthday(new Date());
        user.setAddress("sadfsafsafs");
        user.setSex("男");
        int i = sqlSession.insert("test.insertUser", user);
        sqlSession.commit();
        System.out.println(user.getId());
    }

3.5、更新用户

User.xml:

<!-- 更新 -->
<update id="updateUserById" parameterType="com.long.pojo.User">
    update user 
    set username = #{username},sex = #{sex},birthday = #{birthday},address = #{address}
    where id = #{id}
</update>

测试程序:

//更新用户
    @Test
    public void testUpdateUserById() throws Exception {
        //加载核心配置文件
        String resource = "sqlMapConfig.xml";
        InputStream in = Resources.getResourceAsStream(resource);
        //创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        //创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //执行Sql语句 
        User user = new User();
        user.setId(29);
        user.setUsername("雏田");
        user.setBirthday(new Date());
        user.setAddress("222222sadfsafsafs");
        user.setSex("女");
        int i = sqlSession.update("test.updateUserById", user);
        sqlSession.commit();
    }

3.6、删除用户

User.xml:

<!-- 删除 -->
    <delete id="deleteUserById" parameterType="Integer">
        delete from user 
        where id = #{vvvvv}
    </delete>

测试程序:

//删除
    @Test
    public void testDelete() throws Exception {
        //加载核心配置文件
        String resource = "sqlMapConfig.xml";
        InputStream in = Resources.getResourceAsStream(resource);
        //创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        //创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        sqlSession.delete("test.deleteUserById", 29);
        sqlSession.commit();
    }

四、Mybatis特点

4.1、Mybatis解决jdbc编程的问题

1、数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。
解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库链接。
2、Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
3、向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
4、对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。

4.2、mybatis与hibernate不同

Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。可严格控制sql执行性能,灵活度高。
缺点:mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。

五、原始DAO开发

原始Dao开发方法需要程序员编写Dao接口和Dao实现类。
Dao接口:

public interface UserDao {
    //通过用户ID查询一个用户
    public User selectUserById(Integer id);
}

Dao接口实现类:

public class UserDaoImpl implements UserDao {
    //注入
    private SqlSessionFactory sqlSessionFactory;
    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }
    //通过用户ID查询一个用户
    public User selectUserById(Integer id){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        return sqlSession.selectOne("test.findUserById", id);
    }   
}

测试代码:

public class MybatisDaoTest {
    public SqlSessionFactory sqlSessionFactory;
    @Before
    public void before() throws Exception {
        //加载核心配置文件
        String resource = "sqlMapConfig.xml";
        InputStream in = Resources.getResourceAsStream(resource);
        //创建SqlSessionFactory
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
    }
    @Test
    public void testDao() throws Exception {
        UserDao userDao = new UserDaoImpl(sqlSessionFactory);

        User user = userDao.selectUserById(10);
        System.out.println(user);
    }
}

原始Dao开发中存在以下问题:
(1)Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法
(2)调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不得不开发维护。

六、Mapper动态代理方式

Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper接口开发需要遵循以下规范:
1、Mapper.xml文件中的namespace与mapper接口的类路径相同。
2、Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
4、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
定义映射文件UserMapper.xml:

<mapper namespace="com.long.mapper.UserMapper">
    <!-- 通过ID查询一个用户 -->
    <select id="findUserById" parameterType="Integer" resultType="User">
        select * from user where id = #{v}
    </select>

User接口:

public interface UserMapper {
    //遵循四个原则
    //接口 方法名  == UserMapper.xml 中 id 名
    //返回值类型  与  UserMapper.xml文件中返回值类型要一致
    //方法的入参类型 与UserMapper.xml中入参的类型要一致
    //命名空间 绑定此接口即<mapper namespace="com.long.mapper.UserMapper">
    public User findUserById(Integer id);
}

测试代码:

public class MybatisMapperTest {
    @Test
    public void testMapper() throws Exception {
        //加载核心配置文件
        String resource = "sqlMapConfig.xml";
        InputStream in = Resources.getResourceAsStream(resource);
        //创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        //创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //SqlSEssion帮我生成一个实现类  (给接口)
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        User user = userMapper.findUserById(10);
        System.out.println(user);
    }
}

7、SqlMapConfig.xml配置文件

7.1、properties(属性)

db.properties配置文件内容如下:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root

SqlMapConfig.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>
    <!-- 是用resource属性加载外部配置文件 -->
    <properties resource="db.properties">
        <!-- 在properties内部用property定义属性 -->
        <!-- 如果外部配置文件有该属性,则内部定义属性被外部属性覆盖 -->
        <property name="jdbc.username" value="root123" />
        <property name="jdbc.password" value="root123" />
    </properties>

    <!-- 和spring整合后 environments配置将废除 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>

    <!-- 加载映射文件 -->
    <mappers>
        <mapper resource="sqlmap/User.xml" />
        <mapper resource="mapper/UserMapper.xml" />
    </mappers>
</configuration>

7.2、typeAliases(类型别名)

自定义别名
在SqlMapConfig.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>
    <!-- 是用resource属性加载外部配置文件 -->
    <properties resource="db.properties">
        <!-- 在properties内部用property定义属性 -->
        <property name="jdbc.username" value="root123" />
        <property name="jdbc.password" value="root123" />
    </properties>

    <typeAliases>
        <!-- 单个别名定义 -->
        <typeAlias alias="user" type="cn.long.pojo.User" />
        <!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
        <package name="cn.long.mybatis.pojo" />
        <!-- <package name="其它包" /> -->
    </typeAliases>

    <!-- 和spring整合后 environments配置将废除 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>

    <!-- 加载映射文件 -->
    <mappers>
        <mapper resource="sqlmap/User.xml" />
        <mapper resource="mapper/UserMapper.xml" />
    </mappers>
</configuration>

在mapper.xml配置文件中,就可以使用设置的别名了,别名大小写不敏感。

<mapper namespace="com.long.mapper.UserMapper">
    <!-- 通过ID查询一个用户 -->
    <select id="findUserById" parameterType="Integer" resultType="UsER">
        select * from user where id = #{v}
    </select>
</mapper>

7.3、mappers(映射器)

7.3.1、<mapper resource=" " />
使用相对于类路径的资源(现在的使用方式)
如:<mapper resource="sqlmap/User.xml" />
7.3.2、<mapper class=" " />
使用mapper接口类路径如:<mapper class="cn.long.UserMapper"/>
此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
7.3.3、<package name=""/>
注册指定包下的所有mapper接口
如:<package name="cn.long.mapper"/>
此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

转载请标明出处,原文地址:https://blog.csdn.net/weixin_41835916
总结整理不容易,如果觉得本文对您有帮助,请点击支持一下,您的支持是我写作最大的动力,谢谢。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/weixin_41835916/article/details/80890575