首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >MyBatis 源码学习笔记(一)- MyBatis概述

MyBatis 源码学习笔记(一)- MyBatis概述

作者头像
RiemannHypothesis
发布于 2022-08-19 08:04:10
发布于 2022-08-19 08:04:10
24000
代码可运行
举报
文章被收录于专栏:ElixirElixir
运行总次数:0
代码可运行

一、JDBC

使用JDBC访问数据库的步骤

  1. 定义数据库驱动以及连接信息
  2. 注册数据库驱动
  3. 获取数据库连接
  4. 创建一个查询
  5. 定义执行的SQL
  6. 执行SQL,获取ResultSet结果集
  7. 从结果集中取出数据
  8. 关闭连接
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class JdbcTest {
    // 1.定义数据库驱动以及连接信息
    private static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";
    private static final String JDBC_URL = "jdbc:mysql://rm-uf67r962043910k193o.mysql.rds.aliyuncs.com:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true";
    private static final String JDBC_USER = "root";
    private static final String JBDC_PASSWORD = "Abc*123456";

    public static void main(String[] args) {

        Connection connection = null;
        Statement statement = null;
        try {
            //2.注册数据库驱动
            Class.forName(JDBC_DRIVER);
            //3.获取数据库连接
            connection = DriverManager.getConnection(JDBC_URL,JDBC_USER,JBDC_PASSWORD);
            //4.创建一个查询
            statement = connection.createStatement();
            //5.定义执行的SQL
            String sql = "SELECT * FROM t_user";
            //6.执行SQL,获取ResultSet结果集
            ResultSet resultSet = statement.executeQuery(sql);
            //7.从结果集中取出数据
            List<User> userList = new ArrayList<>();
            while (resultSet.next()){
                User user = new User();
            user.setId(resultSet.getInt("id"));
            user.setUserName(resultSet.getString("user_name"));
                user.setRealName(resultSet.getString("real_name"));
                user.setSex(resultSet.getByte("sex"));
                user.setMobile(resultSet.getString("mobile"));
                user.setEmail(resultSet.getString("email"));
                user.setNote(resultSet.getString("note"));

                System.out.println(user.toString());

                userList.add(user);
            }

            // 8.关闭连接
            connection.close();
            statement.close();
            resultSet.close();
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            try {
                if (statement != null)
                    statement.close();
            } catch (SQLException se2) {
            }// nothing we can do
            try {
                if (connection != null)
                    connection.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }

    }
}
复制代码

上述代码中使用Statement对象执行的查询,如果SQL语句中有参数占位符建议使用PreparedStatement对象来执行查询,PreparedStatement对象可以对SQL语句进行预编译,可以放置SQL注入;而且性能相对Statement会更好些。Jdbc针对数据库写操作需要对事务进行提交。

JDBC访问数据库存在的弊端:

  • 操作数据库步骤繁琐
  • 代码和SQL语句耦合
  • 连接资源需要手动关闭,会有隐患

二、ORM

对象关系映射(ORM),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换

ORM的优势:

  • 更加贴合面向对象编程语意
  • 技术和业务解耦
  • 自动关闭数据库连接,释放资源

HIBERNATE  🆚  MyBatis

MyBatis是一个半自动ORM框架,除了Entity实体类和数据库表的映射关系外,还需要在XML文件中编写SQL语句

MyBatis映射文件三要素:

  • Entity
  • 映射规则
  • SQL

三、MyBatis Quickstart

创建Maven项目mybatis-quick-start,加入相关依赖

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.16</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.14</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.18</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.7</version>
    </dependency>
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>5.3.0</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>
复制代码

在resource目录下创建mybatis-config配置文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?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" />

   <settings>
      <setting name="mapUnderscoreToCamelCase" value="true" />
   </settings>

   <!--配置environment环境 -->
   <environments default="development">
      <!-- 环境配置1,每个SqlSessionFactory对应一个环境 -->
      <environment id="development">
         <transactionManager type="JDBC" />
         <dataSource type="UNPOOLED">
            <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>  
复制代码

在resource目录下创建数据库连接信息的配置文件db.properties

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
jdbc_driver=com.mysql.cj.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
jdbc_username=root
jdbc_password=root
复制代码

在数据库创建t_user表,并插入一条数据,sql如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255) DEFAULT NULL,
  `real_name` varchar(255) DEFAULT NULL,
  `sex` varchar(255) DEFAULT NULL,
  `mobile` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `note` varchar(255) DEFAULT NULL,
  `position_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of t_user
-- ----------------------------
BEGIN;
INSERT INTO `t_user` VALUES (1, 'Stark', 'Tony Stark', '1', NULL, NULL, NULL, NULL);
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;
复制代码

MyBatis开发步骤:

编写Entity实体类 -> 编写Mapper接口 -> 编写对应Mapper.xml文件 -> 测试Mapper接口

在entity包下编写Entity实体类TUser

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Data
public class User {
    private Integer id;
    private String userName;
    private String realName;
    private Byte sex;
    private String mobile;
    private String email;
    private String note;
    private Integer positionId;
}    
复制代码

在mapper包下编写Mapper接口 TUserMapper,定义一个方法,根据主键查询

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface TUserMapper {
    User selectByPrimaryKey(Integer id);
}
复制代码

在resource目录下创建mappers目录,新增TUserMapper.xml映射文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?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.lilith.mapper.UserMapper">
   <select id="selectByPrimaryKey" resultType="com.lilith.entity.User" parameterType="int">
      select
         id, 
         user_name,
         real_name,
         sex, 
         mobile, 
         email, 
         note,
         position_id
      from t_user
      where id = #{id}
   </select>

</mapper>
复制代码

在mybatis-config.xml配置文件中增加Mapper XML文件映射配置,在configuration标签下增加mapper标签

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<mappers>
   <mapper resource="mappers/UserMapper.xml"/>
</mappers>
复制代码

在test包中增加测试类UserMapperTest,测试selectByPrimaryKey()方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class UserMapperTest {

    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void init() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 1.读取mybatis配置文件创SqlSessionFactory
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        inputStream.close();
    }

    @Test
    public void selectByPrimaryKey() throws IOException {
        // 2.获取sqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 3.获取对应mapper
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        // 4.执行查询语句并返回结果
        TUser user = mapper.selectByPrimaryKey(1);
        System.out.println(user);

    }
}
复制代码

控制台打印结果如下

MyBatis的执行流程如下:

MyBatis 的关键对象:

  • SqlSessionFactoryBuilder:可以通过读取配置信息,调用builder方法创建SqlSessionFactory
  • SqlSessionFactory:通过调用openSession()方法创建SqlSession,工程单例模式,存在于程序的整个声明周期
  • SqlSession:代表一次数据库连接,可以直接发送SQL执行,也可以通过调用Mapper访问数据库,线程不安全,要保证线程独享(方法级)
  • Mapper:是由一个Java接口和 XML文件组成的,包含了要执行SQL语句和结果映射规则,方法级声明周期
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-12-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
【高并发】亿级流量场景下如何为HTTP接口限流?看完我懂了!!
作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。自开源半年多以来,已成功为十几家中小型企业提供了精准定时调度方案,经受住了生产环境的考验。为使更多童鞋受益,现给出开源框架地址:
冰河
2020/10/29
8930
【高并发】亿级流量场景下如何为HTTP接口限流?看完我懂了!!
spring 学习(三):aop 学习
3 aop底层使用动态代理实现 (1)第一种情况,有接口情况,使用动态代理创建接口实现类代理对象 (2)第二种情况,没有接口情况,使用动态代理创建类的子类代理对象
希希里之海
2018/08/30
5190
spring 学习(三):aop 学习
基于Reids与AOP实现的定时任务锁-ScheduledLock
简单来说就是通过aop环绕切片将需要加锁的方法包起来,然后在执行前往redis中用setIfAbsent写入一个key,如果返回true,说明没有其他服务正在执行该方法,就继续执行,如果返回false,说明已经有其他服务正在执行该方法,就不执行。
Diuut
2022/11/22
7110
Spring AOP及事务配置三种模式详解
Spring AOP的设计思想,就是通过动态代理,在运行期对需要使用的业务逻辑方法进行增强。
用户4268038
2021/11/18
3590
一不小心,弄了一个开源组件:caffeine+redis实现的多级缓存自定义注解组件
大家好,我是小义,这段时间有点事耽搁了,好久没写文章了,今天介绍一下如何构建一个基于springboot实现的自定义starter组件,即一个可灵活配置过期时间的多级缓存框架。
程序员小义
2024/08/10
4250
一起来学SpringBoot | 第二十七篇:优雅解决分布式限流
在前面的两篇文章中,介绍了一些限流的类型和策略,本篇从 SpringBoot、 Redis 应用层面来实现分布式的限流....
battcn
2018/08/14
3.3K0
一起来学SpringBoot | 第二十七篇:优雅解决分布式限流
SpringBoot利用限速器RateLimiter实现单机限流
一. 概述 参考开源项目https://github.com/xkcoding/spring-boot-demo 在系统运维中, 有时候为了避免用户的恶意刷接口, 会加入一定规则的限流, 本Demo使用速率限制器com.xkcoding.ratelimit.guava.annotation.RateLimiter实现单机版的限流 二. SpringBootDemo 2.1 依赖 <dependency> <groupId>org.springframework.boot</grou
用户7741497
2022/03/24
1.5K0
如何实现一个SpringBoot Starter
Starter是SpringBoot中的一个非常重要的概念,Starter相当于模块,它能将模块所需的依赖整合起来并对模块内的Bean根据条件进行自动配置。 使用者只需要依赖相应功能的Starter,无需做过多的配置和依赖,SpringBoot就能自动扫描并加载相应的模块。 例如我们在创建SpringBoot项目时,经常会引入如spring-boot-starter-web这种依赖,该依赖为我们做了很多默认配置, 无需再依赖spring-web、spring-webmvc等相关包及做相关配置就能够立即使用它。
wo.
2021/06/15
5830
如何实现一个SpringBoot Starter
Guava RateLimiter 实现 API 限流,这才是正确的姿势!
Guava提供的RateLimiter可以限制物理或逻辑资源的被访问速率,咋一听有点像java并发包下的Samephore,但是又不相同,RateLimiter控制的是速率,Samephore控制的是并发量。
JAVA葵花宝典
2021/10/20
10.7K0
Spring AOP入门使用详解
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/149583.html原文链接:https://javaforall.cn
全栈程序员站长
2022/07/05
2410
JAVA高并发 Redis+Lua限流实战
但是我们也知道,限流器在每次请求令牌和放入令牌操作中,存在一个协同的问题,即获取令牌操作要尽可能保证原子性,否则无法保证限流器是否能正常工作。在RateLimiter的实现中使用了mutex作为互斥锁来保证操作的原子性,那么在redis中就需要一个类似于事务的机制来保证获取令牌中多重操作的原子性。 面对这样的需求,我们有几个选择:
小东啊
2019/06/26
3.4K0
JAVA高并发 Redis+Lua限流实战
想通关分布式系统「限流问题」?来一篇源码实战
在分布式领域,我们难免会遇到并发量突增,对后端服务造成高压力,严重甚至会导致系统宕机。为避免这种问题,我们通常会为接口添加限流、降级、熔断等能力,从而使接口更为健壮。Java领域常见的开源组件有Netflix的hystrix,阿里系开源的sentinel等,都是蛮不错的限流熔断框架。
程序员鹏磊
2019/12/10
5070
极简!一个注解就能创建Jaeger的Span
本篇概览 在《Jaeger开发入门(java版)》一文中,咱们编码实现了span的创建和上报,如下图红框,虽然代码量不大,但是把这些代码写在业务代码中,侵入性太强,很多程序员都不喜欢: 今天咱们试试AOP+自定义注解来解决上述问题,如下图,mock是个普通方法,添加了红框中的注解@MySpan,就会创建span然后上报到Jaeger,mock方法的代码没有任何改动: 通过上面两图的对比,可见注解非常简洁,接下来就实战上述手段,具体的步骤如下: 新建web工程,里面有controller层,调用ser
程序员欣宸
2021/12/07
3390
极简!一个注解就能创建Jaeger的Span
SpringBoot 通过自定义注解实现AOP切面编程实例
一直心心念的想写一篇关于AOP切面实例的博文,拖更了许久之后,今天终于着手下笔将其完成。
翎野君
2023/05/12
1.3K0
SpringBoot 通过自定义注解实现AOP切面编程实例
【高并发】亿级流量场景下如何实现分布式限流?看完我彻底懂了!!
作者个人研发的在高并发场景下,提供的简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。自开源半年多以来,已成功为十几家中小型企业提供了精准定时调度方案,经受住了生产环境的考验。为使更多童鞋受益,现给出开源框架地址:
冰河
2020/10/29
6350
【高并发】亿级流量场景下如何实现分布式限流?看完我彻底懂了!!
SpringBoot - 优雅的实现【流控】
限流 简言之就是当请求达到一定的并发数或速率,就对服务进行等待、排队、降级、拒绝服务等操作。
小小工匠
2022/03/01
1.6K0
SpringBoot - 优雅的实现【流控】
分布式限流之Redis+Lua实现
【转载请注明出处】:https://cloud.tencent.com/developer/article/1623236
后端老鸟
2020/05/04
7330
分布式限流之Redis+Lua实现
SpringBoot 服务接口限流方案
在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。限流可以认为服务降级的一种,限流通过限制请求的流量以达到保护系统的目的。
Jensen_97
2023/07/20
1.3K0
SpringBoot 服务接口限流方案
spring aop的五大通知类
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/106636.html原文链接:https://javaforall.cn
全栈程序员站长
2022/08/04
7950
spring aop的五大通知类
Spring AOP 切面编程记录日志和接口执行时间
最近客户现在提出系统访问非常慢,需要优化提升访问速度,在排查了nginx、tomcat内存和服务器负载之后,判断是数据库查询速度慢,进一步排查发现是因为部分视图和表查询特别慢导致了整个系统的响应时间特别长。知道了问题之后,就需要对查询比较慢的接口进行优化,但哪些接口需要优化、哪些不需要呢?只能通过日志里的执行时间来判断,那么如何才能知道每一个接口的执行时间呢?
java架构师
2018/12/27
1.4K0
推荐阅读
相关推荐
【高并发】亿级流量场景下如何为HTTP接口限流?看完我懂了!!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档