0


【Mybatis】2—Mybatis基本用法

⭐⭐⭐⭐⭐⭐
Github主页👉https://github.com/A-BigTree
笔记链接👉https://github.com/A-BigTree/Code_Learning
⭐⭐⭐⭐⭐⭐

如果可以,麻烦各位看官顺手点个star~😊

如果文章对你有所帮助,可以点赞👍收藏⭐支持一下博主~😆


文章目录

3 Mybatis基本用法

3.1 HelloWorld

3.1.1 物理建模

CREATEDATABASE`mybatis-example`;USE`mybatis-example`;CREATETABLE`t_emp`(
  emp_id INTAUTO_INCREMENT,
  emp_name CHAR(100),
  emp_salary DOUBLE(10,5),PRIMARYKEY(emp_id));INSERTINTO`t_emp`(emp_name,emp_salary)VALUES("tom",200.33);INSERTINTO`t_emp`(emp_name,emp_salary)VALUES("jerry",666.66);INSERTINTO`t_emp`(emp_name,emp_salary)VALUES("andy",777.77);

3.1.2 逻辑建模

创建Maven项目加入依赖

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.26</version><scope>compile</scope></dependency>

创建Java实体类

实体类是和现实世界中某一个具体或抽象的概念对应,是软件开发过程中,为了管理现实世界中的数据而设计的模型。 实体类的多个不同的叫法:

  • domain:领域模型;
  • entity:实体;
  • POJO:Plain Old Java Object;
  • Java bean:一个Java类;
/**
 * 和数据库表 t_emp 对应的实体类
 * emp_id INT AUTO_INCREMENT
 * emp_name CHAR(100)
 * emp_salary DOUBLE(10,5)
 *
 * Java 的实体类中,属性的类型不要使用基本数据类型,要使用包装类型。因为包装类型可以赋值为null,表示空,而基本数据类型不可以。
 */@Data@NoArgsConstructor@AllArgsConstructorpublicclassEmployee{privateInteger empId;privateString empName;privateDouble empSalary;}

3.1.3 搭建框架环境

导入依赖

<!-- Mybatis核心 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version></dependency><!-- junit测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.3</version></dependency>

配置文件

Mybatis全局配置文件:

习惯上命名为

mybatis-config.xml

,这个文件名仅仅只是建议,并非强制要求。将来整合Spring之后,这个配置文件可以省略,所以大家操作时可以直接复制、粘贴。

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPEconfigurationPUBLIC"-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 --><environmentsdefault="development"><!-- environment表示配置Mybatis的一个具体的环境 --><environmentid="development"><!-- Mybatis的内置的事务管理器 --><transactionManagertype="JDBC"/><!-- 配置数据源 --><dataSourcetype="POOLED"><!-- 建立数据库连接的具体信息 --><propertyname="driver"value="com.mysql.cj.jdbc.Driver"/><propertyname="url"value="jdbc:mysql://localhost:3306/mybatis-example"/><propertyname="username"value="root"/><propertyname="password"value="atguigu"/></dataSource></environment></environments><mappers><!-- Mapper注册:指定Mybatis映射文件的具体位置 --><!-- mapper标签:配置一个具体的Mapper映射文件 --><!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 --><!--    对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 --><mapperresource="mappers/EmployeeMapper.xml"/></mappers></configuration>
  • 注意:配置文件存放的位置是src/main/resources目录下

Mybatis 映射配置文件:

相关概念:ORM(Object Relationship Mapping)对象关系映射。

  • 对象:Java的实体类对象;
  • 关系:关系型数据库;
  • 映射:二者之间的对应关系;

下表列举的是最简单的单表映射(一个表和一个类):
Java概念数据库概念类表属性字段/列对象记录/行
**注意:

EmployeeMapper.xml

所在的目录要和

mybatis-config.xml

中使用

mapper

标签配置的一致。**

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- mapper是根标签,namespace属性:在Mybatis全局范围内找到一个具体的Mapper配置 --><!-- 引入接口后,为了方便通过接口全类名来找到Mapper配置文件,所以通常将namespace属性设置为接口全类名 --><mappernamespace="com.atguigu.mybatis.dao.EmployeeMapper"><!-- 编写具体的SQL语句,使用id属性唯一的标记一条SQL语句 --><!-- resultType属性:指定封装查询结果的Java实体类的全类名 --><selectid="selectEmployee"resultType="com.atguigu.mybatis.entity.Employee"><!-- Mybatis负责把SQL语句中的#{}部分替换成“?”占位符,在#{}内部还是要声明一个见名知意的名称 -->
        select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{empId}
    </select></mapper>

3.1.4 测试代码

@TestpublicvoidtestSelectEmployee()throwsIOException{// 1.创建SqlSessionFactory对象// ①声明Mybatis全局配置文件的路径String mybatisConfigFilePath ="mybatis-config.xml";// ②以输入流的形式加载Mybatis配置文件InputStream inputStream =Resources.getResourceAsStream(mybatisConfigFilePath);// ③基于读取Mybatis配置文件的输入流创建SqlSessionFactory对象SqlSessionFactory sessionFactory =newSqlSessionFactoryBuilder().build(inputStream);// 2.使用SqlSessionFactory对象开启一个会话SqlSession session = sessionFactory.openSession();// 3.根据Mapper配置文件的名称空间+SQL语句的id找到具体的SQL语句// 格式是:名称空间.SQL语句的idString statement ="com.atguigu.mybatis.dao.EmployeeMapper.selectEmployee";// 要传入SQL语句的参数Integer empId =1;// 执行SQL语句Object result = session.selectOne(statement, empId);System.out.println("o = "+ result);// 4.关闭SqlSession
  session.close();}

说明:

  • SqlSession:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话);
  • SqlSessionFactory:是“生产”SqlSession的“工厂”;
  • 工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”我们需要的对象;

在这里插入图片描述

3.2 HelloWorld强化

3.2.1 加入日志

在Mybatis工作过程中,通过打印日志的方式,将要执行的SQL语句打印出来。

加入依赖

<!-- 日志 --><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency>

加入配置文件

<?xml version="1.0" encoding="UTF-8"?><configurationdebug="true"><!-- 指定日志输出的位置,ConsoleAppender表示输出到控制台 --><appendername="STDOUT"class="ch.qos.logback.core.ConsoleAppender"><encoder><!-- 日志输出的格式 --><!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 --><pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern><charset>UTF-8</charset></encoder></appender><!-- 设置全局日志级别。日志级别按顺序分别是:TRACE、DEBUG、INFO、WARN、ERROR --><!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 --><rootlevel="INFO"><!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender --><appender-refref="STDOUT"/></root><!-- 根据特殊需求指定局部日志级别 --><loggername="com.atguigu.mybatis"level="DEBUG"/></configuration>

修改测试代码

这里我们仅仅修改查询结果的打印方式,为此需要做两件事:

  • 在类上加@Slf4j注解;
  • 使用Logger对象打印数据;
if(result !=null){
    log.info(result.toString());}

3.2.2 关联外部属性文件

在实际开发时,同一套代码往往会对应多个不同的具体服务器环境。使用的数据库连接参数也不同。为了更好的维护这些信息,我们建议把数据库连接信息提取到Mybatis全局配置文件外边。

创建属性文件

wechat.dev.driver=com.mysql.jdbc.Driver
wechat.dev.url=jdbc:mysql://192.168.198.100:3306/mybatis-example
wechat.dev.username=root
wechat.dev.password=atguigu
    
wechat.test.driver=com.mysql.jdbc.Driver
wechat.test.url=jdbc:mysql://192.168.198.150:3306/mybatis-example
wechat.test.username=root
wechat.test.password=atguigu
    
wechat.product.driver=com.mysql.jdbc.Driver
wechat.product.url=jdbc:mysql://192.168.198.200:3306/mybatis-example
wechat.product.username=root
wechat.product.password=atguigu

引入属性文件中的值

Mybatis

全局配置文件中指定外部

jdbc.properties

文件的位置。

<propertiesresource="jdbc.properties"/>

引用属性文件中的值

在需要具体属性值的时候使用${key}格式引用属性文件中的键

<dataSource type="POOLED">
    <!-- 建立数据库连接的具体信息(引用了外部属性文件中的数据) -->
    <property name="driver" value="${wechat.dev.driver}"/>
    <property name="url" value="${wechat.dev.url}"/>
    <property name="username" value="${wechat.dev.username}"/>
    <property name="password" value="${wechat.dev.password}"/>
</dataSource>

3.2.3 用上Mapper接口

Mybatis中的

Mapper

接口相当于以前的Dao。但是区别在于,Mapper仅仅只是建接口即可,我们不需要提供实现类。该用法的思路如下图所示:

在这里插入图片描述

测试类中抽取代码

这一步和Mapper接口没关系,只是对代码本身的优化:

privateSqlSession session;// junit会在每一个@Test方法前执行@Before方法@Beforepublicvoidinit()throwsIOException{
         session =newSqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")).openSession();}// junit会在每一个@Test方法后执行@After方法@Afterpublicvoidclear(){
        session.commit();
        session.close();}

声明Mapper接口

publicinterfaceEmployeeMapper{EmployeeselectEmployee(Integer empId);}
  • 方法名和SQL的id一致;
  • 方法返回值和resultType一致;
  • 方法的参数和SQL的参数一致;
  • 接口的全类名和映射配置文件的名称空间一致;

测试方法

@TestpublicvoidtestUsrMapperInterface(){// 1.根据EmployeeMapper接口的Class对象获取Mapper接口类型的对象EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);// 2.调用EmployeeMapper接口的方法完成对数据库的操作Employee emp = employeeMapper.selectEmployee(1);// 3.打印查询结果if(emp !=null)
        log.info(emp.toString());}

3.3 给SQL语句传参

3.3.1

#{}

形式

Mybatis会将SQL语句中的

#{}

转换为问号占位符。

3.3.2

${}

形式

${}

形式传参,底层Mybatis做的是字符串拼接操作。

通常不会采用

${}

的方式传值。 一个特定的适用场景是:通过Java程序动态生成数据库表,表名部分需要Java程序通过参数传入;而JDBC对于表名部分是不能使用问号占位符的,此时只能使用

${}

。 结论:实际开发中,能用

#{}

实现的,肯定不用

${}

3.4 数据输入

3.4.1 MyBatis总体机制概括

在这里插入图片描述

3.4.2 概括说明

这里数据输入具体是指上层方法(例如Service方法)调用Mapper接口时,数据传入的形式。

  • 简单类型:只包含一个值的数据类型 - 基本数据类型:int、byte、short、double、……- 基本数据类型的包装类型:Integer、Character、Double、……- 字符串类型:String
  • 复杂类型:包含多个值的数据类型 - 实体类类型:Employee、Department、……- 集合类型:List、Set、Map、……- 数组类型:int[]、String[]、……- 复合类型:List、实体类中包含集合……

3.4.3 单个简单类型参数

抽象方法声明

EmployeeselectEmployee(Integer empId);

SQL语句

<selectid="selectEmployee"resultType="com.atguigu.mybatis.entity.Employee">

  select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{empId}

</select>

单个简单类型参数,在

#{}

中可以随意命名,但是没有必要。通常还是使用和接口方法参数同名

3.4.4 实体类型参数

抽象方法声明

intinsertEmployee(Employee employee);

SQL语句

<insertid="insertEmployee">

  insert into t_emp(emp_name,emp_salary) values(#{empName},#{empSalary})

</insert>

在这里插入图片描述

Mybatis会根据

#{}

中传入的数据,加工成

getXxx()

方法,通过反射在实体类对象中调用这个方法,从而获取到对应的数据。填充到

#{}

解析后的问号占位符这个位置。

3.4.5 零散的简单数据类型

抽象方法声明

intupdateEmployee(@Param("empId")Integer empId,@Param("empSalary")Double empSalary);

SQL语句

<updateid="updateEmployee">

  update t_emp set emp_salary=#{empSalary} where emp_id=#{empId}

</update>

3.4.6 Map类型参数

抽象方法声明

intupdateEmployeeByMap(Map<String,Object> paramMap);

SQL语句

<updateid="updateEmployeeByMap">

  update t_emp set emp_salary=#{empSalaryKey} where emp_id=#{empIdKey}

</update>

测试

@TestpublicvoidtestUpdateEmpNameByMap(){EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);Map<String,Object> paramMap =newHashMap<>();

  paramMap.put("empSalaryKey",999.99);

  paramMap.put("empIdKey",5);int result = mapper.updateEmployeeByMap(paramMap);

  log.info("result = "+ result);}

使用场景

有很多零散的参数需要传递,但是没有对应的实体类类型可以使用。使用@Param注解一个一个传入又太麻烦了。所以都封装到Map中。

3.5 数据输出

数据输出总体上有两种形式:

  • 增删改操作返回的受影响行数:直接使用 int 或 long 类型接收即可
  • 查询操作的查询结果

3.5.1 返回单个简单类型数据

抽象方法

intselectEmpCount();

SQL语句

<selectid="selectEmpCount"resultType="int">

  select count(*) from t_emp

</select>

Mybatis内部给常用的数据类型设定了很多别名。 以

int

类型为例,可以写的名称有:

int

integer

Integer

java.lang.Integer

Int

INT

INTEGER

等等。

3.5.2 返回实体类对象

抽象方法

EmployeeselectEmployee(Integer empId);

SQL语句

<!-- 编写具体的SQL语句,使用id属性唯一的标记一条SQL语句 --><!-- resultType属性:指定封装查询结果的Java实体类的全类名 --><selectid="selectEmployee"resultType="com.atguigu.mybatis.entity.Employee"><!-- Mybatis负责把SQL语句中的#{}部分替换成“?”占位符 --><!-- 给每一个字段设置一个别名,让别名和Java实体类中属性名一致 -->
  select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{maomi}

</select>

通过给数据库表字段加别名,让查询结果的每一列都和Java实体类中属性对应起来。

增加配置自动识别对应关系

在 Mybatis 全局配置文件中,做了下面的配置,select语句中可以不给字段设置别名

<!-- 在全局范围内对Mybatis进行配置 --><settings><!-- 具体配置 --><!-- 从org.apache.ibatis.session.Configuration类中可以查看能使用的配置项 --><!-- 将mapUnderscoreToCamelCase属性配置为true,表示开启自动映射驼峰式命名规则 --><!-- 规则要求数据库表字段命名方式:单词_单词 --><!-- 规则要求Java实体类属性名命名方式:首字母小写的驼峰式命名 --><settingname="mapUnderscoreToCamelCase"value="true"/></settings>

3.5.3 返回Map类型

适用于SQL查询返回的各个字段综合起来并不和任何一个现有的实体类对应,没法封装到实体类对象中。能够封装成实体类类型的,就不使用Map类型。

抽象方法

Map<String,Object>selectEmpNameAndMaxSalary();

SQL语句

<!-- Map<String,Object> selectEmpNameAndMaxSalary(); --><!-- 返回工资最高的员工的姓名和他的工资 --><selectid="selectEmpNameAndMaxSalary"resultType="map">

  SELECT
    emp_name 员工姓名,
    emp_salary 员工工资,
    (SELECT AVG(emp_salary) FROM t_emp) 部门平均工资
  FROM t_emp WHERE emp_salary=(
    SELECT MAX(emp_salary) FROM t_emp
  )

</select>

3.5.4 返回List类型

查询结果返回多个实体类对象,希望把多个实体类对象放在List集合中返回。此时不需要任何特殊处理,在resultType属性中还是设置实体类类型即可。

抽象方法

List<Employee>selectAll();

SQL语句

<!-- List<Employee> selectAll(); --><selectid="selectAll"resultType="com.atguigu.mybatis.entity.Employee">

  select emp_id empId,emp_name empName,emp_salary empSalary
  from t_emp

</select>

3.5.5 返回自增主键

返回场景

例如:保存订单信息。需要保存

Order

对象和

List<OrderItem>

。其中,

OrderItem

对应的数据库表,包含一个外键,指向

Order

对应表的主键。

在保存

List<OrderItem>

的时候,需要使用下面的SQL:

insertinto t_order_item(item_name,item_price,item_count,order_id)values(...)

这里需要用到的order_id,是在保存Order对象时,数据库表以自增方式产生的,需要特殊办法拿到这个自增的主键值。至于,为什么不能通过查询最大主键的方式解决这个问题,参考下图:

在这里插入图片描述

SQL语句

<!-- int insertEmployee(Employee employee); --><!-- useGeneratedKeys属性字面意思就是“使用生成的主键” --><!-- keyProperty属性可以指定主键在实体类对象中对应的属性名,Mybatis会将拿到的主键值存入这个属性 --><insertid="insertEmployee"useGeneratedKeys="true"keyProperty="empId">

  insert into t_emp(emp_name,emp_salary)
  values(#{empName},#{empSalary})

</insert>

Mybatis是将自增主键的值设置到实体类对象中,而不是以Mapper接口方法返回值的形式返回

不支持自增主键的数据库

而对于不支持自增型主键的数据库(例如 Oracle),则可以使用 selectKey 子元素:selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用

<insertid="insertEmployee"parameterType="com.atguigu.mybatis.beans.Employee"databaseId="oracle"><selectKeyorder="BEFORE"keyProperty="id"resultType="integer">

    select employee_seq.nextval from dual 

  </selectKey>  

  insert into orcl_employee(id,last_name,email,gender) values(#{id},#{lastName},#{email},#{gender})

</insert>

或者是

<insertid="insertEmployee"parameterType="com.atguigu.mybatis.beans.Employee"databaseId="oracle"><selectKeyorder="AFTER"keyProperty="id"resultType="integer">

    select employee_seq.currval from dual 

  </selectKey>  

  insert into orcl_employee(id,last_name,email,gender) values(employee_seq.nextval,#{lastName},#{email},#{gender})

</insert>

3.5.6 使用resultMap

使用resultMap标签定义对应关系,再在后面的SQL语句中引用这个对应关系

<!-- 专门声明一个resultMap设定column到property之间的对应关系 --><resultMapid="selectEmployeeByRMResultMap"type="com.atguigu.mybatis.entity.Employee"><!-- 使用id标签设置主键列和主键属性之间的对应关系 --><!-- column属性用于指定字段名;property属性用于指定Java实体类属性名 --><idcolumn="emp_id"property="empId"/><!-- 使用result标签设置普通字段和Java实体类属性之间的关系 --><resultcolumn="emp_name"property="empName"/><resultcolumn="emp_salary"property="empSalary"/></resultMap><!-- Employee selectEmployeeByRM(Integer empId); --><selectid="selectEmployeeByRM"resultMap="selectEmployeeByRMResultMap">

  select emp_id,emp_name,emp_salary from t_emp where emp_id=#{empId}

</select>

本文转载自: https://blog.csdn.net/weixin_53580595/article/details/130018675
版权归原作者 一棵___大树 所有, 如有侵权,请联系我们删除。

“【Mybatis】2—Mybatis基本用法”的评论:

还没有评论