mybatis学习2

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定义输出结果的类型。

 

mybatis与hibernate不同

Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。mybatis可以通过XML或注解方式灵活配置要运行的sql语句,

并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。

 

Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件

企业运营类软件等, 因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据

库的软件则需要自定义多套sql映射文件,工作量大。

 

Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。

但是Hibernate的学习门槛高, 要精通门槛更高, 而且怎么设计O/R映射,在性能和对象模型之间如何权衡, 以及怎样用好Hibernate需要具有很强的经验和能力才行。

总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。

 

Dao开发方法

使用MyBatis开发Dao,通常有两个方法,即原始Dao开发方法和Mapper动态代理开发方法。

原始Dao问题 每次都要创建session  里面 命名空间重复

原始Dao开发方式

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

复制代码
public class UserDaoImpl implements UserDao {
    private SqlSessionFactory sqlSessionFactory;
    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {this.sqlSessionFactory = sqlSessionFactory;
    }
    @Override
    public User queryUserById(int id) {
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("queryUserById", id);
        sqlSession.close();
        return user;
    }
    @Override
    public List<User> queryUserByUsername(String username) {
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
        List<User> list = sqlSession.selectList("queryUserByUsername", username);
        sqlSession.close();
        return list;
    }
    @Override
    public void saveUser(User user) {
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
        sqlSession.insert("saveUser", user);
        sqlSession.commit();
        sqlSession.close();
    }
}
复制代码
复制代码
public class UserDaoTest {
    private SqlSessionFactory sqlSessionFactory;
    @Test
    public void testQueryUserByUsername() {
        UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
        List<User> list = userDao.queryUserByUsername("张");
        for (User user : list) {
            System.out.println(user);
        }
    }

    @Test
    public void testSaveUser() {
        UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
        User user = new User();
        user.setUsername("刘备");
        user.setBirthday(new Date());
        user.setSex("1");
        user.setAddress("蜀国");
        userDao.saveUser(user);
        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的类型相同

没有实现类  只有动态代理接口   注意这是Mybatis 提供的功能

遵循原则

  1. 接口 方法名 = User.xml id的名字(就是功能的方法)
  2. 返回值类型  与  Mapper.xml文件中返回值类型要一致
  3. 方法的入参类型 与Mapper.xml中入参的类型要一致

命名空间 绑定此接口  namespace 通常是接口全名

复制代码
<?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:命名空间,用于隔离sql -->
<!-- 还有一个很重要的作用,使用动态代理开发DAO,1. namespace必须和Mapper接口类路径一致 -->
<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
    <!-- 根据用户id查询用户 -->
    <!-- 2. id必须和Mapper接口方法名一致 -->
    <!-- 3. parameterType必须和接口方法参数类型一致 -->
    <!-- 4. resultType必须和接口方法返回值类型一致 -->
    <select id="queryUserById" parameterType="int"
        resultType="cn.itcast.mybatis.pojo.User">
        select * from user where id = #{id}
    </select>

    <!-- 保存用户 -->
    <insert id="saveUser" parameterType="cn.itcast.mybatis.pojo.User">
        <selectKey keyProperty="id" keyColumn="id" order="AFTER"
            resultType="int">
            select last_insert_id()
        </selectKey>
        insert into user(username,birthday,sex,address) values
        (#{username},#{birthday},#{sex},#{address});
    </insert>
</mapper>
复制代码

Dao接口  UserMapper

public interface UserMapper {
    User queryUserById(int id);
    List<User> queryUserByUsername(String username);
    void saveUser(User user);
}

加载UserMapper.xml文件

<!-- 加载映射文件 -->
    <mappers>
        <mapper resource="sqlmap/User.xml" />
        <mapper resource="mapper/UserMapper.xml" />
    </mappers>
复制代码
public class UserMapperTest {
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void init() throws Exception {
        // 创建SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 加载SqlMapConfig.xml配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 创建SqlsessionFactory
        this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    }

    @Test
    public void testQueryUserById() {
        // 获取sqlSession,和spring整合后由spring管理
        SqlSession sqlSession = this.sqlSessionFactory.openSession();

        // 从sqlSession中获取Mapper接口的代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 执行查询方法
        User user = userMapper.queryUserById(1);
        System.out.println(user);

        // 和spring整合后由spring管理
        sqlSession.close();
    }

    @Test
    public void testQueryUserByUsername() {
        // 获取sqlSession,和spring整合后由spring管理
        SqlSession sqlSession = this.sqlSessionFactory.openSession();

        // 从sqlSession中获取Mapper接口的代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 执行查询方法
        List<User> list = userMapper.queryUserByUsername("张");
        for (User user : list) {
            System.out.println(user);
        }
        // 和spring整合后由spring管理
        sqlSession.close();
    }

    @Test
    public void testSaveUser() {
        // 获取sqlSession,和spring整合后由spring管理
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
        // 从sqlSession中获取Mapper接口的代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 创建保存对象
        User user = new User();
        user.setUsername("刘备");
        user.setBirthday(new Date());
        user.setSex("1");
        user.setAddress("蜀国");
        // 执行查询方法
        userMapper.saveUser(user);
        System.out.println(user);

        // 和spring整合后由spring管理
        sqlSession.commit();
        sqlSession.close();
    }
}
复制代码

 

API的学习

SqlSession的使用

SqlSession中封装了对数据库的操作如:增删改查

SqlSession通过SqlSessionFactory创建。

SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。

 

SqlSessionFactoryBuilder

SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory

创建的。所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

 

SqlSessionFactory

SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,

通常以单例模式管理SqlSessionFactory。

 

SqlSession

SqlSession是一个面向用户的接口,sqlSession中定义了数据库操作方法。

每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。

绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。

 

打开一个 SqlSession,使用完毕就要关闭它,通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。

SqlSession session = sqlSessionFactory.openSession();
try {
     // do work
} finally {
    session.close();
}

 

小结:

动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,

如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。

 

mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入

参数可以使用pojo包装对象或map对象,保证dao的通用性。  findUserById(PojoVo vo)

 

SqlMapConfig.xml配置文件

配置的内容和顺序如下

properties 属性

settings 全局配置参数  设置二级缓存和懒加载的 现在没什么用了

typeAliases类型别名

typeHandlers类型处理器

objectFactory对象工厂

plugins插件

environments环境集合属性对象

    environment环境子属性对象

         transactionManager事务管理

         dataSource数据源

mappers (映射器)

 

properties(属性)

SqlMapConfig.xml可以引用java属性文件中的配置信息如下,例如:db.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>
</configuration>
复制代码

注意:MyBatis 将按照下面的顺序来加载属性

1. 在 properties 元素内部定义的属性首先被读取。

2. 然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。

 

typeAliases(类型别名)

通途: 给全类名 起别名

mybatis支持别名: 默认支持的别名  2种都可以

byte long short  int double float boolean Syting Byte Long Short Integer Double Float   Boolean Date BigDecimal  Map


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>
    <typeAliases>
        <!-- 单个别名定义 -->
        <typeAlias alias="user" type="cn.itcast.mybatis.pojo.User" />
        <!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
        <package name="cn.itcast.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>
</configuration>
复制代码

这样在mapper.xml配置文件中,就可以使用设置的别名了

别名大小写不敏感

 

Hibernate 二级缓存 和mybites 缓存都废弃了 因为可以使用redis做分布式缓存

 

mappers(映射器)

<mapper resource=" " /> 

使用相对于类路径的资源(现在的使用方式)

<mapper class=" " />    使用mapper接口类路径

<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>

注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中

 

url 的方法指定没什么意义

 

<package name=""/>  项目当中也是使用这个

注册指定包下的所有mapper接口  mappers里面

如:<package name="cn.itcast.mybatis.mapper"/>       使用包扫描的方式

注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

          缺点 必须要放在一起 并且 名称要相同

 

Hibernate 二级缓存 和mybites 缓存都废弃了 因为有分布式缓存

posted @   escapist  阅读(148)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示