互联网轻量级框架整合之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.rhkb.cn/news/308341.html

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

相关文章

Axure RP中的相关概念及高保真原型构建方法

1 Axure RP中概念介绍 对于构建高保真原型来说&#xff0c;需要知道事件&#xff08;Event&#xff09;、Case、Action等概念。Axure RP中给出这些概念&#xff0c;是为了方便原型的构建&#xff0c;尤其是高保真原型的构建。 事件&#xff08;Event&#xff09;是附着于控件…

[图解]DDD领域驱动设计伪创新-聚合根03

0 00:00:04,120 --> 00:00:07,267 上次我们说到这个Aggregate 1 00:00:07,267 --> 00:00:10,100 就是聚合体的问题 2 00:00:11,340 --> 00:00:16,170 说问题在&#xff0c;它是把重点放在结点上面 3 00:00:17,580 --> 00:00:18,160 4 00:00:18,470 --> 00:00…

selenium添加代理(有账号密码)

以下为各种尝试的记录&#xff0c;正确实现可直接参考最后一条&#xff01; 1&#xff0c;导入Proxy库来添加capabilities属性&#xff1a;可以访问网站&#xff0c;但ip还是本机ip from selenium import webdriver from selenium.webdriver.chrome.options import Options f…

C语言: 字符串函数(下)

片头 在上一篇中,我们介绍了字符串函数。在这一篇章中&#xff0c;我们将继续学习字符串函数&#xff0c;准备好了吗&#xff1f;开始咯&#xff01; 1.strncpy函数 1.1 strncpy函数的用法 strncpy是C语言中的一个字符串处理函数&#xff0c;它用于将一个字符串的一部分内容…

uniapp区分app、h5、小程序

APP端 标签内 <!-- #ifdef APP-PLUS --><view> APP端 </view> <!-- #endif --> JSCSS内 /*#ifdef APP-PLUS*/console.log(APP端) /*#endif*/ H5端 标签内 <!-- #ifdef H5 --><view> H5端 </view> <!-- #endif --> JSC…

18篇文章带你深入浅出了解亚组交互作用(p for Interaction)及可视化分析

交互作用效应(p for Interaction)在SCI文章中可以算是一个必杀技&#xff0c;几乎在高分的SCI中必出现&#xff0c;因为把人群分为亚组后再进行统计可以增强文章结果的可靠性&#xff0c;进行可视化后可以清晰的表明变量之间的关系。不仅如此&#xff0c;交互作用还可以使用来进…

HTML5学习记录

简介 超文本标记语言&#xff08;HyperText Markup Language&#xff0c;简称HTML&#xff09;&#xff0c;是一种用于创建网页的标准标记语言。 编辑器 下载传送门https://code.visualstudio.com/ 下载编辑器插件 标题 标题通过 <h1> - <h6> 标签进行定义。 …

【C++学习】C++11新特性(第一节)

文章目录 ♫一.文章前言♫二.C11新特性♫一.统一的列表初始化♫二.std::initializer_list♫三.声明♫四.decltype关键字♫五.nullptr♫六.新增加容器---静态数组array、forward_list以及unordered系列♫6.1unordered_map与unoredered_set♫6.2array♫6.3 forward_list&#xff…

深度学习体系结构——CNN, RNN, GAN, Transformers, Encoder-Decoder Architectures算法原理与应用

1. 卷积神经网络 卷积神经网络&#xff08;CNN&#xff09;是一种特别适用于处理具有网格结构的数据&#xff0c;如图像和视频的人工神经网络。可以将其视作一个由多层过滤器构成的系统&#xff0c;这些过滤器能够处理图像并从中提取出有助于进行预测的有意义特征。 设想你手…

计算机组成原理【CO】Ch2 数据的表示和应用

文章目录 大纲2.1 数制与编码2.2 运算方法和运算电路2.3 浮点数的表示和运算 【※】带标志加法器OFSFZFCF计算机怎么区分有符号数无符号数? 【※】存储排列和数据类型转换数据类型大小数据类型转换 进位计数制进制转换2的次幂 各种码的基本特性无符号整数的表示和运算带符号整…

(我的创作纪念日)[MySQL]数据库原理7——喵喵期末不挂科

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;大大会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

50+ Midjourney 美食相关提示词,看了别流口水哦

Midjourney 是一个无限的创意宝藏。通过对提示词的精挑细选&#xff0c;我们就可以从这个宝藏里面挖掘无数的美食创意。有些效果令人惊叹&#xff0c;甚至无法在现实世界中复刻。本文不只是罗列 50 多个提示词&#xff0c;而是对它们进行分门别类&#xff0c;并附上图片。相信你…

ELK、ELKF企业级日志分析系统介绍

前言 随着企业级应用系统日益复杂&#xff0c;随之产生的海量日志数据。传统的日志管理和分析手段&#xff0c;难以做到高效检索、实时监控以及深度挖掘潜在价值。在此背景下&#xff0c;ELK日志分析系统应运而生。"Elastic" 是指 Elastic 公司所提供的一系列与搜索…

C++(3) —— 核心编程

一、内存区分模型 1.1 程序运行前 #include<iostream> using namespace std;// 全局变量 int g_a 10; int g_b 20;// const修饰的全局变量&#xff0c;全局常量 const int c_g_a 10; const int c_g_b 20;int main() {// 全局区// 全局变量、静态变量、常量// 创建普通…

采集某新闻网资讯网站保存PDF

网址&#xff1a;融资总额近3亿美元、药明康德押注&#xff0c;这家抗衰老明星公司有何过人之处-36氪 想要抓取文章内容&#xff0c;但是找不到啊&#xff0c;可能是文字格式的问题&#xff0c;也可能文章内容进行了加密。 在元素中查看&#xff0c;window.initialState返回的就…

【Unity+Python】如何通过Socket进行通信

1、Unity端创建名为UnityClient.cs脚本代码(客户端)&#xff1a; 注意&#xff1a;unity的规则中类&#xff0c;名和脚本文件名需要相同。 using System.Net.Sockets; using System.Text; using UnityEngine;public class UnityClient : MonoBehaviour {TcpClient client;Netw…

CSS核心样式-02-盒模型属性及扩展应用

目录 三、盒模型属性 常见盒模型区域 盒模型图 盒模型五大属性 1. 宽度 width 2. 高度 height 3. 内边距 padding 四值法 三值法 二值法 单值法 案例 4. 边框 border 按照属性值的类型划分为三个单一属性 ①线宽 border-width ②线型 border-style ③边框颜色 bo…

软考高级架构师:随机函数模型

一、AI 讲解 随机函数模型是理解各种随机过程和算法的一个重要概念&#xff0c;在软件工程、算法设计以及系统分析中有着广泛的应用。简而言之&#xff0c;随机函数模型是一种用于描述具有随机性的系统或过程的数学模型&#xff0c;它能够帮助我们预测和分析在不确定性下的系统…

基于java+springboot+vue实现的智能停车计费系统(文末源码+Lw+ppt)23-30

摘 要 随着人们生活水平的高速发展&#xff0c;智能停车计费信息管理方面在近年来呈直线上升&#xff0c;人们也了解到智能停车计费的实用性&#xff0c;因此智能停车计费的管理也逐年递增&#xff0c;智能停车计费信息的增加加大了在管理上的工作难度。为了能更好的维护智能…

MySQL基础入门上篇

MySQL基础 介绍 mysql -uroot -p -h127.0.0.1 -P3306项目设计 具备数据库一定的设计能力和操作数据的能力。 数据库设计DDL 定义 操作 显示所有数据库 show databases;创建数据库 create database db02;数据库名唯一&#xff0c;不能重复。 查询是否创建成功 加入一些…