javaweb实训第六天下午——Mybatis基础(2)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 4.3.2.实现

javaweb实训第六天下午——Mybatis基础(1)https://developer.aliyun.com/article/1415142

4.3.2.实现

核心配置文件:MyBatis-Config.xml
<configuration>
    <!-- 引入配置文件信息,这里不能加classpath:。
    resource:引入类路径下的资源,即classpath,所以不需要写classpath:
    url:引入网络路径或磁盘路径下的资源 
  -->
  <properties resource="db.properties"></properties>
  <!-- 环境们 (很多环境的意思)
    default:默认使用哪一个环境(必需对应一个环境的id)
   -->
  <environments default="development">
    <!-- 一个环境  id:为这个环境取唯一一个id名称 -->
    <environment id="development">
      <!-- 事务管理   type:JDBC(支持事务)/MANAGED(什么都不做) -->
      <transactionManager type="JDBC" />
      <!-- 数据源, 连接池  type(POOLED):MyBatis自带的连接池 -->
      <dataSource type="POOLED">
        <!-- 连接数据库的参数:直接写死的方式 -->
                <!--
        <property name="driver" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql:///mydb" />
        <property name="username" value="root" />
        <property name="password" value="admin" />
                 -->
                <!-- 连接数据库的参数:使用属性文件的方式 -->
                <property name="driver" value="${db.driver}" />
        <property name="url" value="${db.url}" />
        <property name="username" value="${db.username}" />
        <property name="password" value="${db.password}" />
      </dataSource>
    </environment>
  </environments>
   <!-- 这个mappers代表的是相应的ORM映射文件 -->
  <mappers> 
    <mapper resource="cn/itsource/domain/ProductMapper.xml" /> 
  </mappers> 
</configuration> 

属性文件:db.properties

db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql:///test0303
db.username=root
db.password=admin

映射文件:


我们的映射文件(也称之为mapper文件)一般情况下是和它对应的domain实体类在同一个包下;

这个映射文件的名称一般叫做 XxxMapper.xml (Xxx代表的是实体类名称)

例如实体类有:

cn.itsource.domain.Product

映射文件名为:

cn/itsource/domain/ProductMapper.xml


namespace的名称通常是接口的完全限定名;

  1. 除了MyBatis支持的类型,其它的类型都通通使用全限定
<?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的主要功能就是写sql
   mapper:根
   namespace:命令空间 (用来确定唯一)以前这个是可以不加的,现在必需加
     namespace的值:接口的完全限定名
 -->
<mapper namespace="cn.itsource.dao.IProductDao">
  <!-- 
    select :这里面写查询语句
    id:用来确定这条sql语句的唯一
         以后我们确定唯一,也就是找sql语句 : namespace + id
       例: cn.itsource.mybatis.day1._1_hello.IProductDao.get
    parameterType : 传入的参数类型  long:大Long  _long:小long (具体的对应请参见文档)
    resultType : 结果类型(第一条数据返回的对象类型)自己的对象一定是完全限定类名
   -->
  <select id="get" parameterType="long" resultType="cn.itsource.domain.Product">
    select * from product where id = #{id}
  </select>
</mapper> 

入门代码:

@Override
public Product get(Long id) {
  SqlSession session = null;
  try {
    Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        session = sqlSessionFactory.openSession();
    // 两个参数:mapper的nameSpace+id的路径,和需要的参数
    return session.selectOne(NAME_SPACE+"get", id);
  } catch (Exception e) {
    e.printStackTrace();
    throw new RuntimeException("使用get方法出错:" + e.getMessage());
  } finally {
    if (session != null) {
      session.close();
    }
  }
}

4.4.其他实现

package cn.itsource.mybatis._01_hello.dao.impl;
import cn.itsource.mybatis._01_hello.dao.IProductDao;
import cn.itsource.mybatis._01_hello.domain.Product;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.Reader;
import java.util.List;
/**
 * dao实现
 *
 *    insert:添加,事务控制
 *    delete:删除,事务控制
 *    update:修改,事务控制
 *    selectOne:查询一个
 *    SelectList:查询多个
 */
public class ProductDaoImpl implements IProductDao {
    @Override
    public void save(Product product) {
        SqlSession sqlSession = null;
        try {
            //1 准备配置文件 ok
            //2 创建SqlSessionFactory
            Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            //3 获取sqlSession做操作
            sqlSession = sqlSessionFactory.openSession();
            //表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值
            sqlSession.insert("cn.itsource.dao.IProductDao.save",product);
            //提交事物-增删改,数据库存储引擎不能是myIsam,它不支持事务
            sqlSession.commit();
        }catch (Exception e){
            e.printStackTrace();
            sqlSession.rollback();
        }finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
    @Override
    public void remove(Long id) {
        SqlSession sqlSession = null;
        try {
            //1 准备配置文件 ok
            //2 创建SqlSessionFactory
            Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            //3 获取sqlSession做操作
            sqlSession = sqlSessionFactory.openSession();
            //表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值
             sqlSession.delete("cn.itsource.dao.IProductDao.remove",id);
             //提交事物-增删改,数据库存储引擎不能是myIsam,它不支持事务
            sqlSession.commit();
        }catch (Exception e){
            e.printStackTrace();
            sqlSession.rollback();
        }finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
    @Override
    public void update(Product product) {
        SqlSession sqlSession = null;
        try {
            //1 准备配置文件 ok
            //2 创建SqlSessionFactory
            Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            //3 获取sqlSession做操作
            sqlSession = sqlSessionFactory.openSession();
            //表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值
            sqlSession.update("cn.itsource.dao.IProductDao.update",product);
            //提交事物-增删改,数据库存储引擎不能是myIsam,它不支持事务
            sqlSession.commit();
        }catch (Exception e){
            e.printStackTrace();
            sqlSession.rollback();
        }finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }
    @Override
    public Product loadById(Long id) {
        SqlSession sqlSession = null;
        try {
            //1 准备配置文件 ok
            //2 创建SqlSessionFactory
            Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            //3 获取sqlSession做操作
            sqlSession = sqlSessionFactory.openSession();
            //表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值
            return  sqlSession
                    .selectOne("cn.itsource.dao.IProductDao.loadById",id);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
        return null;
    }
    @Override
    public List<Product> loadAll() {
        SqlSession sqlSession = null;
        try {
            //1 准备配置文件 ok
            //2 创建SqlSessionFactory
            Reader reader = Resources.getResourceAsReader("MyBatis-Config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            //3 获取sqlSession做操作
            sqlSession = sqlSessionFactory.openSession();
            //表示调用那句sql(namespace+.+id)-拷贝,传入参数,接收得到返回值
            return  sqlSession
                    .selectList("cn.itsource.dao.IProductDao.loadAll");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
        return null;
    }
}
package cn.itsource.mybatis._01_hello.dao;
import cn.itsource.mybatis._01_hello.dao.impl.ProductDaoImpl;
import cn.itsource.mybatis._01_hello.domain.Product;
import org.junit.Test;
/**
 * 打印快捷方式:obj.sout
 * 快速省略测试:类里面-右键-goto-junit4-勾上
 */
public class IProductDaoTest {
    IProductDao productDao = new ProductDaoImpl();
    @Test
    public void save() {
        Product product = productDao.loadById(18L);
        product.setId(null);
        product.setProductName("yhptest......");
        productDao.save(product);
    }
    @Test
    public void remove() {
        Product product = productDao.loadById(19L);
        System.out.println(product);
        productDao.remove(19L);
        product = productDao.loadById(19L);
        System.out.println(product);
    }
    @Test
    public void update() {
        Product product = productDao.loadById(22L);
        System.out.println(product);
        product.setProductName("yhptest......edit");
        productDao.update(product);
        product = productDao.loadById(22L);
        System.out.println(product);
    }
    @Test
    public void loadById() {
        //obj.sout
        System.out.println(productDao.loadById(1L));
    }
    @Test
    public void loadAll() {
        for (Product product : productDao.loadAll()) {
            System.out.println(product);
        }
    }
}

4.5.注意

配置XML中的约束,使其有提示:

20210602165506417.png

5.Mybatis工具类

5.1.MybatisUtil抽取

5.1.1.为什么要抽取

  1. 其实每个Dao的方法都要获取SQLSession,并且使用完都要关闭,对于像获取和关闭等操作都应该交给工具处理;

5.1.2.抽取理论分析

SqlSessionFactoryBuilder:

建造者模式:我们最后拿到的这个对象是非常复杂的. 用这个建造者就它先为我们把这些复杂的代码完成。这个类可以被实例化,使用和丢弃。一旦你创建了SqlSessionFactory后,这个类对象就不需要存在了。因此SqlSessionFactoryBuilder实例的最佳范围是方法范围(也就是本地方法变量)。你可以重用SqlSessionFactoryBuilder来创建多个SqlSessionFactory实例,但是最好的方式是不需要保持它一直存在来保证所有XML解析资源,因为还有更重要的事情要做;


SqlSessionFactory:

一旦被创建,SqlSessionFactory应该在你的应用执行期间都存在。没有理由来处理或重新创建它。使用SqlSessionFactory的最佳实践是在应用运行期间不要重复创建多次。这样的操作将被视为是非常糟糕的。因此SqlSessionFactory的最佳范围是应用范围。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。然而这两种方法都不认为是最佳实践。这样的话,你可以考虑依赖注入容器,比如Google Guice或Spring。这样的框架允许你创建支持程序来管理单例SqlSessionFactory的生命周期;


SqlSession

每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段甚至是实例字段中。也绝不能将SqlSession实例的引用放在任何类型的管理范围中,比如Serlvet架构中的HttpSession。如果你现在正用任意的Web框架,要考虑SqlSession放在一个和HTTP请求对象相似的范围内。换句话说,基于收到的HTTP请求,你可以打开了一个SqlSession,然后返回响应,就可以关闭它了。关闭Session很重要;

5.1.3.抽取

20210602165548671.png

5.2.使用工具完成CRUD

5.2.1.查询一条数据

sql

代码

5.2.2.查询所有数据

sql

代码

5.2.3.添加一条数据

注意:添加的时候一定要记住提交事务(配置事务、表结构支持事务)

sql

代码

5.2.4.修改一条数据

sql

代码

5.2.5.删除一条数据

sql

代码

6.SQL映射器Mapper

6.1.引入

引入:之前通过Mybatis操作数据库的时候,除了写接口,还要写实现类。MyBatis基于动态代理机制,让我们无需再编写Dao的实现,但是必须要遵循一定的规范:


传统Dao接口,现在名称统一以Mapper结尾:例如:IUserDao --> UserMapper

还有我们映射器配置文件要和映射器在同一个包:

(1)包:cn.itsource.mapper中(UserMapper接口 和 UserMapper.xml)

UserMapper.xml中namespace直接写UserMapper接口的的完全限定名;

20210602165628833.png

映射文件:

<mapper namespace="cn.itsource.mybatis.mapper.UserMapper">
  <select id="接口的方法名" parameterType="long" resultType="User">
Select * from t_user where id = #{id}
</select>
</mapper>

6.2.映射器实现步骤

根据需求,创建模型相关的Mapper接口,例如:UserMapper;

在同包下编写映射文件,例如:UserMapper.xml;

 (1)Mapper映射文件的命名空间,必须和接口的"完全限定名"一致;

 (2)定义sql标签的id,需要和"接口的方法名"一致;

  1. 在Mybatis核心配置文件中配置(或注册)Mapper映射文件;
  2. 测试;
    友情提示:最好不要在mapper接口中使用方法重载,因为sql标签的id即为方法名,写重载方法容易出问题;

6.3.实现

接口实现方式一(传统):

20210602165706148.png

接口实现方式二(映射器):

20210602165709758.png

6.4.添加是返回自增长的ID

一般来说数据库表都有一个主键id,而且是自增长的。在添加数据时,如果不添加id,那么数据库会自动获取当前最大id,将这个 最大id自增1个之后作为即将要添加数据的id值;

有的时候我们在执行insert提交之后,需要获取这个自增id。因为有可能会作为下一次查询的依据,或者下一个插入的外键的凭证;

6.4.1.方式一:

XxxMapper写法:
public interface ProductMapper {
  //自增长ID
  void insert1(Product product);
}
XxxMapper.xml写法:
<!-- 插入数据并返回自增ID
有自增ID功能数据库可以采用useGeneratedKeys="true"开启判断是否是自增ID
keyProperty="id"  指定插入数据后自增ID返回时赋值给实体类的那个属性(这里是id属性)
-->
<!-- void insert1(Product product) -->
<insert id="insert1"  useGeneratedKeys="true" keyProperty="id">
  insert into product(productName) values(#{productName})
</insert>
测试:
@Test
public void testInsert(){
  SqlSession session = MybatisUtil.getSqlSession();
  ProductMapper mapper = session.getMapper(ProductMapper.class);
  Product product = new Product();
  product.setProductName("绿茶111");
  System.out.println("====执行前===="+product.getId());
  mapper.insert1(product);
  System.out.println("====执行后===="+product.getId());
  session.commit();
  session.close();
}

javaweb实训第六天下午——Mybatis基础(3)https://developer.aliyun.com/article/new/database?spm=a2c6h.12873639.article-detail.4.2cd86ab7dyZ9bx&publish=1415631#/

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
2月前
|
SQL Java 数据库连接
JavaWeb基础3——Maven基础&MyBatis
构建工具Maven、Maven安装配置、基本使用、IDEA使用Maven、依赖管理、插件、Mybatis、核心配置文件mybatis-config.xml、Mapper代理开发、配置文件实现增删改查、Mybatis参数传递、注解实现增删改查
JavaWeb基础3——Maven基础&MyBatis
|
5月前
|
SQL XML Java
Javaweb - MyBatis 精华篇
Javaweb - MyBatis 精华篇
31 1
|
5月前
|
SQL Java 数据库连接
*Javaweb -- MyBatis*
*Javaweb -- MyBatis*
|
5月前
|
SQL Java 数据库连接
JavaWeb基础第三章(MyBatis的应用,基础操作与动态SQL)
JavaWeb基础第三章(MyBatis的应用,基础操作与动态SQL)
|
5月前
|
Java 数据库连接 Apache
JavaWeb基础第二章(Maven项目与MyBatis 的快速入门与配置)
JavaWeb基础第二章(Maven项目与MyBatis 的快速入门与配置)
|
6月前
|
SQL XML Java
Javaweb之Mybatis的动态SQLforeach和include的详细解析
Javaweb之Mybatis的动态SQLforeach和include的详细解析
62 0
|
1月前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
110 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
1月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
54 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
1月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
311 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个