互联网轻量级框架整合之MyBatis核心组件

在看本篇内容之前,最好先理解一下Hibernate和MyBatis的本质区别,这篇Hibernate和MyBatis使用对比实例做了实际的代码级对比,而MyBatis作为更适合互联网产品的持久层首选必定有必然的原因

MyBatis核心组件

MyBatis能够成为数据持久层首选框,关键还是在于ORM(Object-Relational Mapping)的特性上:

  • 不屏蔽SQL,这意味着可以更精确的定位SQL语句,可以对其进行优化和改造,非常有利于互联网的高可用和高并发属性,符合互联网产品需要的高性能特点
  • 提供强大、灵活的映射机制,提供动态SQL的特性,允许根据不同条件组装SQL,这个特点远比其他工具或者Java编码的可读性和可维护性更好,满足各种应用系统需求的同时满足了需求经常变化的互联网产品要求
  • 提供Mapper接口编程,只需要一个接口和一个XML就能够构建映射器,进一步简化开发工作,从而可以更聚焦于业务逻辑

MyBatis的核心组件分为4个部分:

  • SqlSessionFactoryBuilder(构造器):根据配置或者代码生成SqlSessionFactory,采用分布构建的Builder模式
  • SqlSessionFactory(工厂接口):生成SqlSession,使用工厂模式
  • SqlSession(会话):既可以发送SQL执行返回结果,也可以获取Mapper的接口,在现有的模式中,通常会使用MyBatis提供的SQL Mapper接口编程技术,以提高代码的可读性和可维护性
  • SqlMapper(映射器):由Java接口和XML文件(或注解)构成,需要给出对应的SQL和映射规则,由他来发送SQL去执行,并返回结果

在这里插入图片描述

SQLSessionFactory

在这里插入图片描述
使用MyBatis需要使用配置或者代码构建SQLSessionFactory(工厂接口)对象,MyBatis提供了构造器SQLSessionFactoryBuilder,而这就是建造者模式,一步构建SQLSessionFactoryBuilder会比较复杂,为了简化这个对象的构建过程,MyBatis提供了一个配置类org.apache.ibatis.session.Configuration作为引导,实际的分步构建过程是在Configuration类里完成的

这里边会有很多其他内容,例如比较复杂的插件等等

构建SQLSessionFactory对象还可以采用读取配置好的XML文件的形式(通过Java代码的形式需要修改则会相对复杂),无论是配置了XML文件或者提供了代码后,MyBatis会读取配置文件,通过Configuration类对象构建整个MyBatis的上下文

  • SQLSessionFactory是一个接口,在MyBatis中存在SQLSessionManager和DefaultSQLSessionFactory两个实现类,前者多用于多线程环境中,通常情况下是使用后者来实现的
  • 每个基于MyBatis的应用都是以一个SQLSessionFactory的实例为中心的,而SQLSessionFactory唯一的作用就是生产MyBatis的核心接口对象SQLSession,因此它的责任是唯一的,在这样的情况下,我们应该只构建一个SQLSessionFactory对象,显然就是一种单例模式
使用XML配置文件构建SQLSessionFactory对象
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTDConfig3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--typeAliases必须放在properties后面,否则会报错 --><properties resource="config.properties"/><typeAliases><typeAlias alias="role" type="com.ssm.pojo.Role" /></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--<property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/ssm1?useUnicode=true;characterEncoding=utf8"/><property name="username" value="root"/><property name="password" value="Ms123!@#"/>--><property name="driver" value="${className}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><mappers><mapper resource="mapper/t_role.xml"/></mappers>
</configuration>

这段XML代码是MyBatis配置文件的示例。

  • typeAliases 定义了类型别名,这里将 com.ssm.Role 类型别名为 Role,定义别名后在MyBatis上下文中就可以使用别名代替全限定名
  • properties 用于加载外部属性文件 config.properties。
  • environments 定义了数据库连接的环境配置,默认使用 development 环境。
  • transactionManager 设置事务管理器类型为 JDBC。
  • dataSource 设置数据源类型为 POOLED,表示采用MyBatis内部提供的连接池方式。
  • mappers 定义了映射文件的位置,这里指定了 mapper/t_role.xml。

有了这个配置就可以用一段代码来构建SQLSessionFactory对象,代码如下

package com.ssm;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.InputStream;/*** 创建SqlSessionFactory类,用于单例模式下创建MyBatis的SqlSessionFactory对象。* 这个类不包含任何参数构造函数,通过静态方法创建SqlSessionFactory实例。*/
public class CreateSqlSessionFactory
{/*** 静态方法,创建并返回一个SqlSessionFactory实例。* 这个方法通过读取配置文件"mybatis-config.xml"来构建SqlSessionFactory。** @return SqlSessionFactory MyBatis的SQL会话工厂对象。*/private static SqlSessionFactory createSqlSessionFactory() {SqlSessionFactory sqlSessionFactory = null; // 初始化SqlSessionFactory为nullString cfgFile = "mybatis-config.xml"; // MyBatis配置文件的路径InputStream inputStream = null; // 初始化输入流为nulltry {// 尝试从资源中加载配置文件的输入流inputStream = Resources.getResourceAsStream(cfgFile);// 使用输入流构建SqlSessionFactorysqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}catch (IOException e){e.printStackTrace(); // 捕获并打印IO异常}return sqlSessionFactory; // 返回构建的SqlSessionFactory实例}
}
使用代码构建SQLSessionFactory对象
    private static SqlSessionFactory createSqlSessionFactoryII(){// 初始化数据源PooledDataSource dataSource = new PooledDataSource();dataSource.setDriver("com.mysql.jdbc.Driver");dataSource.setUsername("root");dataSource.setPassword("123456");dataSource.setUrl("jdbc://localhost:3306/ssm");dataSource.setDefaultAutoCommit(false);// 设置事务工厂和环境配置TransactionFactory transactionFactory = new JdbcTransactionFactory();Environment environment = new Environment("development", transactionFactory, dataSource);// 配置MyBatisConfiguration configuration = new Configuration(environment);// 注册别名,使得在映射文件中可以使用别名代替全类名configuration.getTypeAliasRegistry().registerAlias("role", Role.class);// 添加映射器,用于映射SQL语句到Java方法configuration.addMapper(RoleMapper.class);// 构建SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);return sqlSessionFactory;}

这种方式比较复杂,如果修改代码还需要重新编译等动作,实际上完成了跟XML形式一样的事情,但如果配置文件中配置的是加密后的数据库用户名和密码,需要在构建SQLSessionFactory对象之前进行解密,可以采用这种形式

SQLSession

在MyBatis中,SQLSession也是核心接口之一,在MyBatis中有两个实现类,DefaultSqlSession和SqlSessionManager,DefaultSqlSession是单线程环境下使用,而SqlSessionManager在多线程环境下使用;SqlSession的作用类似于一个JDBC中的Connection对象,代表着一个链接资源的启用,如要作用有3个其一获取Mapper接口、其二给数据库发送SQL、其三控制数据库事务

    public void executeSqlSessionOperation() {// 假设这里是你需要执行的具体逻辑操作// 注意:由于原代码没有具体的业务逻辑,以下代码将展示如何在try-with-resources中结构化处理SqlSessiontry (SqlSession sqlSession = createSqlSessionFactory().openSession()) {// 执行SqlSession中的操作,例如:sqlSession.insert(...); sqlSession.update(...); 等// 提交事务sqlSession.commit();} catch (Exception e) {// 对异常进行处理,这里可以根据不同的异常类型进行更细致的捕获和处理// 例如,对于数据库连接异常、SQL执行异常等,可以进行不同的日志记录或者错误处理e.printStackTrace();// 回滚事务,由于在try块中无法直接访问到SqlSession,所以这里假设异常发生时需要回滚事务// 注意:实际中可能需要更复杂的逻辑来确保事务的正确回滚sqlSession.rollback();}finally {if(sqlSession != null){sqlSession.close();}}}

映射器

映射器是MyBatis中相对复杂的组件,它由一个接口和对应的XML文件(或注解)组成,它可以配置一下内容

  • 描述映射规则
  • 提供SQL语句,并配置SQL参数类型、返回类型、缓存刷新等信息
  • 配置缓存
  • 提供动态SQL

首先定义一个POJO

package com.ssm.pojo;
/*** 角色类,用于表示系统中的角色信息*/
public class Role {private Integer id; // 角色IDprivate String roleName; // 角色名称private String note; // 角色备注信息/*** 获取角色ID* @return 角色的ID值*/public Integer getId() {return id;}/*** 设置角色ID* @param id 角色的新ID值*/public void setId(Integer id) {this.id = id;}/*** 获取角色名称* @return 角色的名称*/public String getRoleName() {return roleName;}/*** 设置角色名称* @param roleName 角色的新名称*/public void setRoleName(String roleName) {this.roleName = roleName;}/*** 获取角色备注信息* @return 角色的备注信息*/public String getNote() {return note;}/*** 设置角色备注信息* @param note 角色的新备注信息*/public void setNote(String note) {this.note = note;}@Overridepublic String toString() {return "Role{" +"id=" + id +", roleName='" + roleName + '\'' +", note='" + note + '\'' +'}';}
}

在Java中,使用private关键字来修饰类的成员变量(如上述Role类中的id, roleName, note)的主要原因如下:

  • 封装性(Encapsulation):这是面向对象编程(OOP)的基本原则之一。将数据成员声明为private意味着它们不能直接被外部访问或修改。这样可以隐藏对象内部实现细节,对外提供一个清晰、稳定的接口。通过只暴露必要的公共方法(如getId(), setId(), getRoleName(), setRoleName()等),控制了对这些私有成员变量的访问和操作,确保了数据的安全性和一致性。
  • 数据保护:private修饰的变量仅能在该类的内部方法中访问和修改。这样可以防止外部代码(如其他类或同一个类的不同实例)意外地更改或错误地使用这些数据,从而避免潜在的数据损坏或逻辑错误。例如,对于id这样的标识符,通常希望其一旦初始化后就不允许随意变更,通过将其设为private并提供无set方法,就可以有效防止外部代码误改。
  • 实现内聚性:将变量设为private并提供对应的getter和setter方法(即访问器和修改器),可以集中处理与这些变量相关的业务逻辑。例如,在setNote()方法中,可以添加额外的校验逻辑(如检查输入字符串是否合法)、触发相关事件(如更新日志记录)或执行其他与设置note属性相关的操作。这样使得类的职责更加明确,提高了代码的内聚性。
  • 灵活性与可维护性:将来如果需要更改Role类内部数据的存储方式(如从使用String存储roleName改为使用枚举类型),或者添加新的约束条件(如限制note的最大长度),由于外部代码仅依赖于提供的公共方法,而不直接操作私有变量,因此无需修改大量外部代码,极大地提高了代码的灵活性和可维护性。

综上所述,将POJO(Plain Old Java Object,简单Java对象)中的变量定义为private,是为了实现面向对象编程中的封装性原则,保护数据安全,增强代码内聚性,以及提高代码的灵活性和可维护性。

MyBatis的映射器的作用主要是在POJO和SQL之间建立映射关系

用XML实现映射器

用XML定义映射器分为接口和XML两部分,首先定义一个映射器接口

package com.ssm.Dao;import com.ssm.pojo.Role;import java.util.List;
/*** 角色数据访问接口*/
public interface RoleDao {/*** 根据角色ID获取角色信息* @param id 角色的唯一标识符* @return 返回对应ID的角色对象,如果不存在则返回null*/public Role getRoleById(Integer id);/*** 根据角色名称获取角色信息* @param name 角色的名称* @return 返回对应名称的角色对象,如果不存在则返回null*/public Role getRoleByName(String name);/*** 新增角色信息* @param role 需要新增的角色对象*/public void insertRole(Role role);/*** 更新角色信息* @param role 需要更新的角色对象*/public void updateRole(Role role);/*** 根据角色ID删除角色信息* @param id 需要删除的角色的唯一标识符*/public void deleteRole(Integer id);/*** 获取所有角色信息* @return 返回所有角色的列表*/public List<Role> findRoles(String roleName);
}

在mybatis-config.xml文件里有一行mapper的配置

    <mappers><mapper resource="mapper/t_role.xml"/></mappers>

其作用是引入一个XML配置文件,通过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的命名空间 -->
<mapper namespace="com.ssm.mapper.RoleMapper"><!-- 定义结果映射,用于将数据库中的数据映射成Role对象 --><resultMap id="roleMap" type="com.ssm.pojo.Role"><id property="id" column="id"/> <!-- 主键映射 --><result property="roleName" column="roleName"/> <!-- 角色名映射 --><result property="note" column="note"/> <!-- 备注映射 --></resultMap><!-- 插入一个新的Role记录 --><insert id="insertRole" parameterType="com.ssm.pojo.Role">INSERT INTO t_role(roleName, note) VALUES (#{roleName}, #{note})</insert><!-- 根据ID查询Role信息,返回Role对象 --><select id="getRoleById" parameterType="int" resultMap="roleMap">SELECT * FROM t_role WHERE id = #{id}</select><!-- 更新Role的信息 --><update id="updateRole" parameterType="com.ssm.pojo.Role">UPDATE t_role SET roleName = #{roleName}, note = #{note} WHERE id = #{id}</update><!-- 根据ID删除一个Role记录 --><delete id="deleteRole" parameterType="int">DELETE FROM t_role WHERE id = #{id}</delete>
</mapper>

有了接口和XML映射文件,就完成了一个映射器的定义,MyBatis在默认情况下提供自动映射功能,只要SQL返回的列名能和POJO对应起来即可;很显然定义映射器只用到了接口,而没有实现类,接口是不能直接运行的,MyBatis是用动态代理技术,来处理了相关的映射逻辑

用注解实现映射器
/*** RoleMapperII接口,用于通过ID获取角色信息*/
package com.ssm.mapper;import com.ssm.pojo.Role;
import org.apache.ibatis.annotations.Select;public interface RoleMapperII {/*** 根据角色ID获取角色详细信息* @param id 角色的唯一标识符* @return 返回对应ID的角色对象*/@Select("select * from role where id = #{id}")public Role getRoleById(Integer id);
}

这完全等同于通过XML方式构建映射器,如果两个方式同时定义时,XML方式将覆盖掉注解方式,如果使用注解的方式则需要在MyBatis基础配置文件中添加mapper接口,和配置XML类似

    <mappers><mapper resource="mapper/t_role.xml"/><mapper class="com.ssm.mapper.RoleMapperII"/></mappers>

并且在代码中使用Configuration对象注册这个映射器接口configuration.addMapper(RoleMapperII.class);

用SQLSession发送SQL

有了映射器就可以通过SQLSession发送SQL了,如下代码所示

Role role=(Role)sqlSession;
selectOne("com.ssm.mapper.RoleMapper.getRoleByID", 1);

selectOne方法表示使用查询并且只返回一个对象,参数一看就很清楚来自哪里,如此字符串对象由一个命名空间加上SQL ID组合而成,它完全定位到了一条SQL,这条语句也可以简化为Role role=(Role)sqlSession.selectOne("getRole",1);这是MyBatis的前身IBATIS留下的方式

用Mapper接口发送SQL

SQLSession还可以获取Mapper接口,用Mapper接口发送SQL,代码如下

RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
Role role = roleMapper.getRole(1);

因为XML文件或者接口注解定义的SQL都可以通过“类的全限定名+方法名”查找,因此MyBatis会启用对应接口执行SQL并返回结果

  • 用注解的形式实现映射器,如果遇到很复杂的SQL,那代码的可读性实在太差了,更严重的如果遇到动态SQL,那就会更加复杂,Java代码和SQL混杂一起,非常难读且难以维护
  • 发送SQL如果使用SQLSession直接发送,那只会在运行过程中才能知道是否会产生错误,而如果使用Mapper的方式发送SQL,IDE会提示错误和校验,并且使用SQLSession发送SQL也会给代码带来一定的复杂度,虽然不至于很难读,但也不那么美观

生命周期

生命周期是MyBatis组件的重要问题,尤其在多线程环境中,控制不好会造成严重的多线程并发或者系统资源浪费问题

  • SQLSessionFactoryBuilder:的作用是构建SQLSessionFactory,构建成功后,SQLSessionFactoryBuilder就失去了作用,所以他只能存在于构建SQLSessionFactory的方法中,而不能长期存在
  • SQLSessionFactory:可以认为它是一个数据库的连接池,其作用是构建SQLSession接口对象,而MyBatis的本质是对数据库的操作,因此SQLSessionFactory的生命周期存在于整个MyBatis的应用中,一旦构建了SQLSessionFactory,就要长期保存,直到不再使用MyBatis应用;而由于SQLSessionFactory相当于一个对数据库的连接池,它占据着数据库的链接资源,如果构建多个SQLSessionFactory,就存在多个连接池,这样不利于对数据库资源的合理使用,容易导致数据库连接多不好管理,数据库资源快速耗光而宕机,因此通常希望只有一个SQLSessionFactory作为单例,然后让他在应用中被共享
  • SQLSession:如果SQLSessionFactory相当于数据库连接池,那么SQLSession就相当于一个数据库连接(Connection对象),用户可以在一个事务里执行多条SQL,然后通过它的commit、rollback等方法进行提交或者回滚事务;SQLSession应该只存在当前业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给SQLSessionFactory,否则数据库资源很快会耗光,导致系统瘫痪,所以需要用try...catch...finally结构体来保证其能够正确关闭并释放诗句哭链接资源
  • Mapper:Mapper是一个接口,由SQLSession构建,所以它的生命周期至多和SQLSession保持一致,会随着SQLSession的关闭而消失,这是合理的,Mapper代表一个业务处理,一旦处理完相关业务,就应该抛弃它

代码示例

在这里插入图片描述

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.ssm</groupId><artifactId>ChapterMybatis</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><name>ChapterMybatis</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.9</version></dependency><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.24.1-GA</version></dependency><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.10</version></dependency><dependency><groupId>org.ow2.asm</groupId><artifactId>asm</artifactId><version>7.0</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.26</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.26</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.11.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency></dependencies>
</project>
package com.ssm.Dao;import com.ssm.pojo.Role;import java.util.List;
/*** 角色数据访问接口*/
public interface RoleDao {/*** 根据角色ID获取角色信息* @param id 角色的唯一标识符* @return 返回对应ID的角色对象,如果不存在则返回null*/public Role getRoleById(Integer id);/*** 根据角色名称获取角色信息* @param name 角色的名称* @return 返回对应名称的角色对象,如果不存在则返回null*/public Role getRoleByName(String name);/*** 新增角色信息* @param role 需要新增的角色对象*/public void insertRole(Role role);/*** 更新角色信息* @param role 需要更新的角色对象*/public void updateRole(Role role);/*** 根据角色ID删除角色信息* @param id 需要删除的角色的唯一标识符*/public void deleteRole(Integer id);/*** 获取所有角色信息* @return 返回所有角色的列表*/public List<Role> findRoles(String roleName);}
package com.ssm.pojo;
/*** 角色类,用于表示系统中的角色信息*/
public class Role {private Integer id; // 角色IDprivate String roleName; // 角色名称private String note; // 角色备注信息/*** 获取角色ID* @return 角色的ID值*/public Integer getId() {return id;}/*** 设置角色ID* @param id 角色的新ID值*/public void setId(Integer id) {this.id = id;}/*** 获取角色名称* @return 角色的名称*/public String getRoleName() {return roleName;}/*** 设置角色名称* @param roleName 角色的新名称*/public void setRoleName(String roleName) {this.roleName = roleName;}/*** 获取角色备注信息* @return 角色的备注信息*/public String getNote() {return note;}/*** 设置角色备注信息* @param note 角色的新备注信息*/public void setNote(String note) {this.note = note;}@Overridepublic String toString() {return "Role{" +"id=" + id +", roleName='" + roleName + '\'' +", note='" + note + '\'' +'}';}
}
package com.ssm.Utils;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.IOException;
import java.io.InputStream;/*** 创建SqlSessionFactory类,用于单例模式下创建MyBatis的SqlSessionFactory对象。* 这个类不包含任何参数构造函数,通过静态方法创建SqlSessionFactory实例。*/
public class SqlSessionFactoryUtils {//同步锁,用于确保线程安全地创建单例SqlSessionFactory对象private final static Class<SqlSessionFactoryUtils> LOCK = SqlSessionFactoryUtils.class;//SqlSessionFactory单例对象private static SqlSessionFactory sqlSessionFactory = null;//私有构造函数,防止外部实例化本类private SqlSessionFactoryUtils(){System.out.println("SqlSessionFactoryUtils类被实例化了");}/*** 静态方法,创建并返回一个SqlSessionFactory实例。* 这个方法通过读取配置文件"mybatis-config.xml"来构建SqlSessionFactory。* 方法是线程安全的,确保了SqlSessionFactory的单例特性。*/public static void getSqlSessionFactory() {synchronized (LOCK) { //使用同步代码块,保证线程安全if (sqlSessionFactory != null) {//如果SqlSessionFactory已经存在,则直接返回,避免重复创建return;}//读取配置文件String configFile = "mybatis-config.xml";InputStream inputStream = null;try {inputStream = Resources.getResourceAsStream(configFile);//基于配置文件构建SqlSessionFactorysqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}}/*** 打开一个SqlSession会话。* 如果SqlSessionFactory尚未创建,则先创建之。** @return 返回一个SqlSession实例。*/public static SqlSession openSqlSession(){//确保SqlSessionFactory已经创建if(sqlSessionFactory ==null){getSqlSessionFactory();}//返回一个新的SqlSession实例return sqlSessionFactory.openSession();}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTDConfig3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--typeAliases必须放在properties后面,否则会报错 --><properties resource="config.properties"/><typeAliases><typeAlias alias="Role" type="com.ssm.pojo.Role"/></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><!--<property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/ssm1?useUnicode=true;characterEncoding=utf8"/><property name="username" value="root"/><property name="password" value="Ms123!@#"/>--><property name="driver" value="${className}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><mappers><mapper resource="mapper/RoleMapper.xml"/><mapper class="com.ssm.Dao.RoleDaoII"/></mappers>
</configuration>
# 此段为配置文件内容,而非函数或类代码,故按行进行注释解释# 指定MySQL连接的驱动类
className=com.mysql.cj.jdbc.Driver# 设置数据库连接的URL,包括数据库地址、端口和数据库名称等信息
url=jdbc:mysql://localhost:3306/ssm1?useUnicode=true&characterEncoding=utf8# 指定数据库的用户名
username=root# 指定数据库的密码
password=Ms123!@#
# 配置文件的根记录器设置
log4j.rootLogger=DEBUG, stdout# 设置org.mybatis包的记录级别为DEBUG
log4j.logger.org.mybatis=DEBUG# 配置标准输出流作为日志的输出目标
log4j.appender.stdout=org.apache.log4j.ConsoleAppender# 配置标准输出流的布局模式
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %d %C: %m%n
# 上述模式为日志输出的格式,%5p表示日志级别,%d表示日期,%C表示类别,%m表示日志消息,%n表示换行
# 下面的注释掉的配置是一种替代的日期格式和日志输出格式
# log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
<?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的命名空间 -->
<mapper namespace="com.ssm.Dao.RoleDao"><!-- 定义结果映射,用于将数据库中的数据映射成Role对象 --><resultMap id="roleMap" type="com.ssm.pojo.Role"><id property="id" column="id"/> <!-- 主键映射 --><result property="roleName" column="roleName"/> <!-- 角色名映射 --><result property="note" column="note"/> <!-- 备注映射 --></resultMap><!-- 插入一个新的Role记录 --><insert id="insertRole" parameterType="com.ssm.pojo.Role">INSERT INTO t_role(roleName, note) VALUES (#{roleName}, #{note})</insert><!-- 根据ID查询Role信息,返回Role对象 --><select id="getRoleById" parameterType="int" resultMap="roleMap">SELECT id, roleName, note FROM t_role WHERE id = #{id}</select><select id="findRoles" parameterType="string" resultMap="roleMap">select id, roleName, note from t_role where roleName like concat ('%',#{roleName},'%')</select><!-- 更新Role的信息 --><update id="updateRole" parameterType="com.ssm.pojo.Role">UPDATE t_role SET roleName = #{roleName}, note = #{note} WHERE id = #{id}</update><!-- 根据ID删除一个Role记录 --><delete id="deleteRole" parameterType="int">DELETE FROM t_role WHERE id = #{id}</delete>
</mapper>
package com.ssm;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import com.ssm.Dao.RoleDao;
import com.ssm.pojo.Role;
import com.ssm.Utils.SqlSessionFactoryUtils;import java.util.List;/*** 主程序类,用于演示通过MyBatis进行数据库操作。*/
public class Main {public static void main(String[] args) {// 获取日志记录器Logger log = Logger.getLogger(Main.class);SqlSession sqlSession = null;try{// 获取SqlSession实例sqlSession = SqlSessionFactoryUtils.openSqlSession();// 通过SqlSession获取RoleDao接口的实现RoleDao roleDao = sqlSession.getMapper(RoleDao.class);// 调用方法查询角色列表List<Role> role = roleDao.findRoles("zhang");// 记录查询结果log.info(role.toString());// 通过ID查询单个角色Role role1 = roleDao.getRoleById(2);// 记录查询结果log.info(role1.toString());// 插入角色到数据库roleDao.insertRole(role1);} finally {// 确保SqlSession在操作完成后关闭if (sqlSession != null){sqlSession.close();}}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/806701.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每日一题(leetcode1702):修改后的最大二进制字符串--思维

找到第一个0之后&#xff0c;对于后面的子串&#xff08;包括那个0&#xff09;&#xff0c;所有的0都能调上来&#xff0c;然后一一转化为10&#xff0c;因此从找到的第一个0的位置开始&#xff0c;接下来是&#xff08;后半部分子串0的个数-1&#xff09;个1&#xff0c;然后…

电力系统卫星授时信号安全隔离装置防护方案

电力系统是国家关键基础设施&#xff0c; 电力安全关系国计民生&#xff0c; 是国家安全的重要保障&#xff0c; 与政治安全、经济安全、 网络安全、社会安全等诸多领域密切关联。电网运行情况瞬息万变&#xff0c;为了在其发生事故时能够及时得到处理&#xff0c;需要统一的时…

vue2 二次封装element 组件,继承组件原属性,事件,插槽 示例

测试页面代码 这里主要记录如何封装element的el-input 并且封装后具有el-input原本的属性 事件 插槽 下面为测试页面即组件调用 <script> import CustomInput from /components/CustomInput.vue;export default {name: TestPage,components: { CustomInput },data() …

jvm中jdk常用的几个命令总结

1.jmap 此命令可以用来查询内存信息&#xff0c;实例个数及占用内存大小 1.1 查看堆内存概要信息&#xff08;内存分配统计&#xff09; jmap -histo[:live] <pid> .-histo&#xff1a;显示堆中对象的统计信息&#xff0c;包括每个类的实例数量、占用内存大小等 :live…

从入门到弃坑:一个后端开发到鸿蒙开发的简单尝试

【摘要】 笔者说&#xff1a;因为本人也从未接触 Android 开发&#xff0c;所以本文也是从小白入门的角度学习 HarmonyOS开发&#xff0c;文中大量的内容和观点其实都可以从官方文档查阅到。写这篇文章大概也是从中精简内容&#xff0c;记录学习 HarmonyOS 的过程。 鸿蒙操作系…

四大生成式模型的比较——GAN、VAE、归一化流和扩散模型

比较四大模型的本质 four modern deep generative models: generative adversarial networks, variational autoencoders, normalizing flows, and diffusion models 待写

基于SpringBoot的“酒店管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“酒店管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统结构图 系统首页界面图 用户注册界面图 个人…

政安晨:【深度学习神经网络基础】(六)—— 前馈神经网络

目录 简述 前馈神经网络结构 计算输出 初始化权重 径向基函数神经网络 径向基函数 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 政安晨的机器学习笔记 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎…

.NET MAUI Android Emulator运行错误 APT2000 系统找不到指定的文件

前言 本地.NET MAUI项目使用Android Emulator&#xff08;安卓模拟器&#xff09;调试运行&#xff0c;提示异常&#xff1a;严重性 代码 说明 项目 文件 行 禁止显示状态 详细信息 错误 APT2000 系统找不到指定的文件。 错误原因 文件目录中不能…

无监督学习~clustering

什么是clustering&#xff1f; 聚类算法查看多个数据点&#xff0c;并自动找到彼此相关或相似的数据点。 K-means clustering 示例 循环&#xff1a;再次分配每个点到离它最近的质心&#xff0c;重新计算质心。 K-means algorithm 注意&#xff1a; k-means的初始化质心Mu有…

大话设计模式之单例模式

单例模式是一种创建型设计模式&#xff0c;它确保类只有一个实例&#xff0c;并提供一个全局访问点来访问该实例。 单例模式通常在以下情况下使用&#xff1a; 当一个类只能有一个实例&#xff0c;并且客户端需要访问该实例时。当该唯一实例需要被公开访问&#xff0c;以便在…

微服务-2 Eureka

Eureka 启动页面&#xff1a; 同理再注册完order-service后&#xff0c;刷新启动页面&#xff1a; userservice 启动多台服务&#xff1a; [ 代码 ]&#xff1a;orderService.java&#xff08;用 RestTemplate 调其他服务&#xff0c;用 userservice 代替 localhost:8081&…

CUDA10安装与卸载,CUDA10.2与MMSEG安装

安装CUDA10 1、因为要用到tensorflow1.15.5的GPU版本&#xff0c;所以想安装cuda10来进行加速&#xff0c;通过nvidia-smi检查本机上的CUDA版本 2、下载的cuda10版本&#xff0c;cuda_10.0.130_411.31_win10.exe 下载的cudnn版本&#xff0c;cudnn-10.0-windows10-x64-v7.6.4…

B站广告推广操作教程及费用?

哔哩哔哩&#xff08;B站&#xff09;作为国内极具影响力的年轻人文化社区&#xff0c;已成为众多品牌与企业触达目标受众、提升品牌影响力的重要阵地。然而&#xff0c;面对B站复杂的广告系统与精细化运营需求&#xff0c;许多广告主可能对如何高效开展B站广告推广感到困惑。云…

备战蓝桥杯---数学刷题3

话不多说&#xff0c;直接看题&#xff1a; 1. 我们可以得到大致一个思路&#xff0c;就是先枚举1-1e6的质数&#xff0c;然后看看有几个即可。 我们怎么知道个数呢&#xff1f; 首先我们知道1---n中有n/p的下取整个为p的倍数。 因此&#xff0c;p的个数至少是n/p的下取整个…

typescript中的type关键字和interface关键字区别

Type又叫类型别名&#xff08;type alias&#xff09;,作用是给一个类型起一个新名字&#xff0c;不仅支持interface定义的对象结构&#xff0c;还支持基本类型、联合类型、交叉类型、元组等任何你需要手写的类型。 type num number; // 基本类型 type stringOrNum string |…

信息系统项目管理师——第5章信息系统工程(三)

近几期的考情来看&#xff0c;本章选择题稳定考4分&#xff0c;考案例的可能性有&#xff0c;需要重点学习。本章节专业知识点特别多。但是&#xff0c;只考课本原话&#xff0c;大家一定要把本章至少通读一遍&#xff0c;还要多刷题&#xff0c;巩固重点知识。 3 系统集成 3…

初识C++之内联函数 auto关键字

初识C之内联函数 auto关键字 文章目录 初识C之内联函数 auto关键字一、 内联函数1.1 定义1.2 应用1.3 特性 二、auto关键字2.1 简介2.2 auto的详细使用2.3 范围for&#xff08;C&#xff09;2.4 注意事项 一、 内联函数 1.1 定义 以inline修饰的函数叫做内联函数&#xff0c;…

python 有哪些函数

Python内置的函数及其用法。为了方便记忆&#xff0c;已经有很多开发者将这些内置函数进行了如下分类&#xff1a; 数学运算(7个) 类型转换(24个) 序列操作(8个) 对象操作(7个) 反射操作(8个) 变量操作(2个) 交互操作(2个) 文件操作(1个) 编译执行(4个) 装饰器(3个) …

linux进阶篇:文件查找的利器——grep命令+管道操作详解

Linux文件查找的利器——grep命令管道操作详解 1 grep简介 grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具&#xff0c;它能使用正则表达式搜索文本&#xff0c;并把匹配的行打印出来。 Uni…