Mybatis使用和原理

embedded/2024/12/29 5:55:28/

Mybatis使用和原理

  • 1、ORM架构
  • 2、Spring整合MyBatis使用
    • 2.1 添加maven依赖
    • 2.2 配置数据源
    • 2.3 创建实体类
    • 2.4 创建 MyBatis Mapper
      • 2.4.1 使用MyBatis注解
      • 2.4.2 使用XML方式
    • 2.5 Service 层
  • 3、Spring整合Hibernate使用
    • 3.1 添加maven依赖
    • 3.2 配置数据源
    • 3.3 创建实体类
    • 3.4 创建 Repository 接口
    • 3.5 创建 Service 层
  • 4、MyBatis字段映射

如有侵权,请联系~
如有错误,也欢迎批评指正~

1、ORM架构

对象关系映射(Object Relational Mapping,简称ORM)架构是为了解决编程语言中对象和数据库中数据不一致的问题,完成对象与数据库的转换。orm除了数据库记录和程序对象的映射以外,还提供操作数据库的封装等。
orm架构位置
优点:
开发效率:通过对象表示数据库,简化了数据库操作。
可读性:代码更接近于业务逻辑,增强了可读性。
数据库独立性:通过 ORM,可以较容易地在不同的数据库间切换。
缺点:
性能开销:在某些情况下,ORM 可能会引入性能问题,特别是在进行复杂查询时。
学习曲线:对于初学者,理解 ORM 的工作原理可能需要时间。

常见的 ORM 框架
Hibernate: Java 中最常用的 ORM 框架,功能强大,支持多种数据库。是一个强大、方便、全自动化【sql都不需要写】的持久化架构。适用于性能要求不高的系统。
MyBatis: MyBatis提供了小巧、高效,半自动化【sql仍然需要写】的持久层架构。半自动化缺点就是需要自己编写sql逻辑,当然这也是优点,可以让用户定制sql。适用于性能要求高、灵活的系统。

2、Spring整合MyBatis使用

2.1 添加maven依赖

<dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- MyBatis Spring Boot Starter --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version> <!-- 使用最新版本 --></dependency><!-- MySQL Driver --><dependency><groupId>sql>mysql</groupId><artifactId>sql>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- Spring Boot Starter Test --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
</dependencies>

2.2 配置数据源

在 src/main/resources/application.yml 或 application.properties 中配置连接数据库的信息。以application.properties为例子:

java">// 数据源部分
spring.datasource.url=jdbc:sql>mysql://localhost:3306/your_database_name  
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.datasource.driver-class-name=com.sql>mysql.cj.jdbc.Drivermybatis.mapper-locations=classpath:mapper/*.xml    // 设置 MyBatis XML 映射文件路径
mybatis.type-aliases-package=com.example.model    // 设置实体类所在的包

2.3 创建实体类

创建一个实体类与数据库表映射。例如,我们创建一个 User 类:

java">package com.example.model;public class User {private Long id;private String name;private Integer age;// Getters and Setterspublic Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}
}

2.4 创建 MyBatis Mapper

创建一个 Mapper 接口,并使用 MyBatis 注解或 XML 文件进行 SQL 操作。

2.4.1 使用MyBatis注解

java">package com.example.mapper;import com.example.model.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;import java.util.List;@Mapper
public interface UserMapper {@Select("SELECT * FROM user")List<User> findAll();
}

2.4.2 使用XML方式

在 src/main/resources/mapper 目录下创建 UserMapper.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">
<mapper namespace="com.example.mapper.UserMapper"><select id="findAll" resultType="com.example.model.User">SELECT * FROM user</select>
</mapper>

创建UserMapper 接口:

java">package com.example.mapper;import com.example.model.User;
import java.util.List;public interface UserMapper {List<User> findAll();
}

2.5 Service 层

创建一个 Service 类调用 Mapper 接口:

java">package com.example.service;import com.example.mapper.UserMapper;
import com.example.model.User;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class UserService {@Autowireprivate final UserMapper userMapper;public List<User> getAllUsers() {return userMapper.findAll();}
}

3、Spring整合Hibernate使用

3.1 添加maven依赖

<dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Data JPA --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- Hibernate Validator for JPA --><dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId></dependency><!-- MySQL Driver --><dependency><groupId>sql>mysql</groupId><artifactId>sql>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- Spring Boot Starter Test --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
</dependencies>

3.2 配置数据源

在 src/main/resources/application.yml 或 application.properties 文件中配置数据库连接信息。以application.properties为例:

java">// 数据源
spring.datasource.url=jdbc:sql>mysql://localhost:3306/your_database_name
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.datasource.driver-class-name=com.sql>mysql.cj.jdbc.Driverspring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

3.3 创建实体类

创建一个实体类,与数据库表映射。例如,我们创建一个 User 类:

java">package com.example.model;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;@Entity
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;private Integer age;// Getters and Setterspublic Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}
}

3.4 创建 Repository 接口

创建一个 Repository 接口,以便与数据库进行交互:

java">package com.example.repository;import com.example.model.User;
import org.springframework.data.jpa.repository.JpaRepository;public interface UserRepository extends JpaRepository<User, Long> {// 可以添加自定义查询方法
}

3.5 创建 Service 层

创建一个 Service 类来调用 Repository 进行业务逻辑处理:

java">package com.example.service;import com.example.model.User;
import com.example.repository.UserRepository;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class UserService {@Autowireprivate UserRepository userRepository;public List<User> getAllUsers() {return userRepository.findAll();}public void saveUser(User user) {userRepository.save(user);}public User getUserById(Long id) {return userRepository.findById(id).orElse(null);}public void deleteUser(Long id) {userRepository.deleteById(id);}
}

4、MyBatis字段映射

ORM框架主要的作用之一就是对象和数据库记录的映射。MyBatis就是从ResultSet结果集中获取到sql记录,然后将记录映射到自定义的java对象。MyBatis映射的方式:

  • 使用列名直接进行映射,这也是默认的方式。这需要java的属性名和sql>mysql字段名保持一致。
  • 使用别名映射。select查询之后使用as给列起别名
  • 使用ResultMap进行映射。ResultMap实现查询结果与java对象映射
  • 自定义TypeHandler映射,java实现BaseTypeHandler。

主要三大步:
1、通过反射创建对象。进行字段映射的核心类DefaultResultSetHandler,创建java对象通过反射创建的:

java">private  <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {try {Constructor<T> constructor;if (constructorArgTypes == null || constructorArgs == null) {constructor = type.getDeclaredConstructor();if (!constructor.isAccessible()) {constructor.setAccessible(true);}return constructor.newInstance();}constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));if (!constructor.isAccessible()) {constructor.setAccessible(true);}// 这里创建对象return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));} catch (Exception e) {StringBuilder argTypes = new StringBuilder();if (constructorArgTypes != null && !constructorArgTypes.isEmpty()) {for (Class<?> argType : constructorArgTypes) {argTypes.append(argType.getSimpleName());argTypes.append(",");}argTypes.deleteCharAt(argTypes.length() - 1); // remove trailing ,}StringBuilder argValues = new StringBuilder();if (constructorArgs != null && !constructorArgs.isEmpty()) {for (Object argValue : constructorArgs) {argValues.append(String.valueOf(argValue));argValues.append(",");}argValues.deleteCharAt(argValues.length() - 1); // remove trailing ,}throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);}}

2、使用resultMap将resultSet中的数据解析出数据。这个类会根据上述说的映射方式resultMap进行映射,其实上述这么多映射方式,最终都是转换为TypeHandler类【子类,如LongTypeHandler、LocalDateTypeHandler】

java">public class DefaultResultSetHandler implements ResultSetHandler {@Overridepublic List<Object> handleResultSets(Statement stmt) throws SQLException {ErrorContext.instance().activity("handling results").object(mappedStatement.getId());final List<Object> multipleResults = new ArrayList<Object>();int resultSetCount = 0;// 获取sql查询到的结果集ResultSetWrapper rsw = getFirstResultSet(stmt);// 所有配置的映射规则List<ResultMap> resultMaps = mappedStatement.getResultMaps();int resultMapCount = resultMaps.size();validateResultMapsCount(rsw, resultMapCount);while (rsw != null && resultMapCount > resultSetCount) {ResultMap resultMap = resultMaps.get(resultSetCount);// 进行映射处理,存储到multipleResults中handleResultSet(rsw, resultMap, multipleResults, null);rsw = getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount++;}String[] resultSets = mappedStatement.getResultSets();if (resultSets != null) {while (rsw != null && resultSetCount < resultSets.length) {ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);if (parentMapping != null) {String nestedResultMapId = parentMapping.getNestedResultMapId();ResultMap resultMap = configuration.getResultMap(nestedResultMapId);handleResultSet(rsw, resultMap, null, parentMapping);}rsw = getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount++;}}return collapseSingleResultList(multipleResults);}private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {try {if (parentMapping != null) {handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);} else {if (resultHandler == null) {DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);// 处理映射存储到defaultResultHandler中handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);multipleResults.add(defaultResultHandler.getResultList());} else {handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);}}} finally {// issue #228 (close resultsets)closeResultSet(rsw.getResultSet());}}public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {if (resultMap.hasNestedResultMaps()) {ensureNoRowBounds();checkResultHandler();handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);} else {handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);}}// 最终执行这个方法private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)throws SQLException {final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);boolean foundValues = false;final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();for (ResultMapping propertyMapping : propertyMappings) {String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);if (propertyMapping.getNestedResultMapId() != null) {// the user added a column attribute to a nested result map, ignore itcolumn = null;}if (propertyMapping.isCompositeResult()|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))|| propertyMapping.getResultSet() != null) {// 这里会根据java对象的类型使用不同的xxxTypeHandler获取valueObject value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);// issue #541 make property optionalfinal String property = propertyMapping.getProperty();if (property == null) {continue;} else if (value == DEFERED) {foundValues = true;continue;}if (value != null) {foundValues = true;}if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {// gcode issue #377, call setter on nulls (value is not 'found')// 将value赋值给属性metaObject.setValue(property, value);}}}return foundValues;}
}

3、利用反射将对象给对象相关属性赋值。将获取到的数据利用反射给create好的对象赋值:

java">private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {try {Invoker method = metaClass.getSetInvoker(prop.getName());Object[] params = {value};try {method.invoke(object, params);} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}} catch (Throwable t) {throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t);}}

http://www.ppmy.cn/embedded/133962.html

相关文章

好音质的百元头戴式耳机怎么选?四款高音质百元头戴式耳机推荐

选头戴式耳机的时候&#xff0c;品牌的选择常常让人犹豫不决。因为市面上的头戴式耳机品牌繁多&#xff0c;从知名的大牌到新兴的科技品牌&#xff0c;各种型号层出不穷&#xff0c;价格跨度也相当大。面对这些琳琅满目的选择&#xff0c;好音质的百元头戴式耳机怎么选&#xf…

爬虫+数据保存2

爬取数据保存到MySQL数据库 这篇文章, 我们来讲解如何将我们爬虫爬取到的数据, 进行保存, 而且是把数据保存到MySQL数据库的方式去保存。 目录 1.使用pymysql连接数据库并执行插入数据sql代码(insert) 2.优化pymysql数据库连接以及插入功能代码 3.爬取双色球网站的数据并保…

三种SPI机制的了解及使用

文章目录 1.SPI机制概念2.Java SPI2.1 创建一个项目&#xff0c;并创建如下模块2.2 db-api模块2.3 mysql-impl模块2.4 oracle-impl模块2.5 main-project模块 3.Spring SPI4.Dubbo SPI 1.SPI机制概念 SPI全程Service Provider Interface&#xff0c;是一种服务发现机制。 SPI的…

【网络】2.TCP通信

TCP通信 server1. 创建套接字2. 填充套接字3. 将套接字和监听文件描述符绑定4. 将_listensock设置为监听状态5. 启动服务器accept()函数read()函数 Server启动client1. 创建套接字2. 填充套接字connect()函数 3. 通过文件描述符向服务端发送信息 client启动 server server的启…

HTB:BoardLight[WriteUP]

目录 连接至HTB服务器并启动靶机 1.How many TCP ports are listening on BoardLight? 2.What is the domain name used by the box? 3.What is the name of the application running on a virtual host of board.htb? 4.What version of Dolibarr is running on Board…

群晖通过 Docker 安装 Firefox

1. 获取 firefox 镜像 在注册表搜索 jlesage/firefox&#xff0c;并且下载 2. 创建容器 运行映像 jlesage/firefox&#xff0c;开始创建容器 3. 配置容器 启用自动重新启动&#xff0c;重点配置存储空间和环境变量&#xff0c;其他默认。 创建文件夹&#xff0c;及子文件夹…

NavVis VLX三维激光扫描仪在市政地形测绘中的典型应用【沪敖3D】

项目&#xff1a;市政地形测绘 市政地形测绘涵盖了特定区域内的自然与人为特征&#xff0c;如道路、建筑物、桥梁等户外环境和结构。这一过程为各种工程、建筑、施工及土地开发项目提供了准确、全面的景观数据。 地形测绘常常是建设项目的首要步骤。因其普遍性&#xff0c;地…

基于yolov8的柑橘叶片病虫害检测系统,支持图像、视频和摄像实时检测【pytorch框架、python源码】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; 基于yolov8的柑橘叶片病虫害检测系统&#xff0c;支持图像、视频和摄像实时检测【pytorch框架、python源码】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov8的柑橘叶片病虫害检测系…