互联网轻量级框架整合之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();}}}
}
相关文章:
互联网轻量级框架整合之MyBatis核心组件
在看本篇内容之前,最好先理解一下Hibernate和MyBatis的本质区别,这篇Hibernate和MyBatis使用对比实例做了实际的代码级对比,而MyBatis作为更适合互联网产品的持久层首选必定有必然的原因 MyBatis核心组件 MyBatis能够成为数据持久层首选框&a…...
springboot websocket 持续打印 pod 日志
springboot 整合 websocket 和 连接 k8s 集群的方式参考历史 Java 专栏文章 修改前端页面 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>Java后端WebSocket的Tomcat实现</title><script type"text/javasc…...
C代码编译过程与进程内存分布
C代码编译过程 在这篇文章中,我们将探讨C语言代码的编译流程以及进程在运行时的内存布局。编译过程通常包括几个关键步骤:预处理、编译、汇编和链接。 预处理阶段主要是处理源代码文件中的宏定义、头文件包含和条件编译指令。在此阶段,编译…...
Windows 部署ChatGLM3大语言模型
一、环境要求 硬件 内存:> 16GB 显存: > 13GB(4080 16GB) 硬盘:60G 软件 python 版本推荐3.10 - 3.11 transformers 库版本推荐为 4.36.2 torch 推荐使用 2.0 及以上的版本,以获得最佳的推理性能 二、部…...
JS相关八股之什么是事件循环
在JavaScript中,“事件循环”(Event Loop)是一个非常重要的概念,它是指JavaScript引擎如何在单线程中处理异步操作的机制。单线程意味着在任意时刻,JavaScript代码只能执行一个任务。 一.事件循环的工作流程大致如下&…...
SpringCloud集成Skywalking链路追踪和日志收集
1. 下载Agents https://archive.apache.org/dist/skywalking/java-agent/9.0.0/apache-skywalking-java-agent-9.0.0.tgz 2. 上传到服务器解压 在Spring Cloud项目中,每部署一个服务时,就拷贝一份skywalking的agent文件到该服务器上并解压。不管是部署…...
HTTP 域名和主机是一回事吗?有了主机和域名,如何建站?
域名不等于主机名,例如baidu.com是一个权威域的域名,但是根本没有一个主机的名字叫做baidu.com,但是dns.baidu.com就是一个主机名,它就是负责baidu.com的服务器的主机名,www.baidu.com也是一个主机名,它是百度web服务器的主机名。…...
运营干货:四个技巧掌握爆款选题方法
在运营工作中,选题是一项至关重要的工作,选对了一个热门话题,就能吸引大量用户的关注和互动,从而取得更好的运营成果。 今天,就给大家分享四个爆款选题方法,让大家的运营更上一层楼! 第一种&a…...
柯桥商务口语之怎么样说英语更加礼貌?十个礼貌用语get起来!
当你在国外需要帮助的时候,这些礼貌用语真的是能够帮到你的哦 1.Would/Could you help me? 你可帮助我吗? 相信有些人想请求帮助的时候,一开口就用Can you,这个用在朋友或者熟人上面当然是没有问题的,但是如果是向…...
嵌入式工程师如何摸鱼?
有老铁问我,做嵌入式开发要加班吗? 也不知道搞什么鬼,现在的年轻人对加班这么抵触。 我刚做开发那会,啥也不懂,每天基本都要加班到晚上7-9点不等,我并不抵触加班,因为早早回家,也没什…...
C++语言题库(一)—— 基本知识类
目录 1. Hello World! 2. 据说一个人的标准体重应该是其身高(单位:厘米)减去100、再乘以0.9所得到的公斤数。已知市斤的数值是公斤数值的两倍。现给定某人身高,请你计算其标准体重应该是多少? 3. 给定一个华氏温度F…...
gemini1.5 API调用
https://ai.google.dev/pricing?hlzh-cn 查询可用的model https://generativelanguage.googleapis.com/v1beta/models?keyxxx 使用postman调用 https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro-latest:generateContent?keyxxx https://ai.google…...
C++从入门到精通——const与取地址重载
const与取地址重载 前言一、const正常用法const成员函数问题const对象可以调用非const成员函数吗非const对象可以调用const成员函数吗const成员函数内可以调用其它的非const成员函数吗非const成员函数内可以调用其它的const成员函数吗总结 二、取地址及const取地址操作符重载概…...
手写spring IOC底层源码来模拟spring如何利用多级缓存解决循环依赖的问题
在文章开始之前,先来看一张spring IOC加载过程的脑图吧 Spring IOC的加载过程 首先,当我们去new了一个applicationContext,它底层呢就会把我们配置的bean进行扫描,然后创建成一个一个的beanDefinition放在我们的beanDefinitionMap中,此时就有了一切创造bean的原料信…...
C++11 Thead线程和线程池
参考资料: 2、5.lock_guard 与 std::unique_lock-陈子青的编程学习课堂 (seestudy.cn) 3、C11 多线程编程-小白零基础到手撕线程池_哔哩哔哩_bilibili 一、 C11 Thead线程库的基本使用 # include <thread> std::thread t(function_name, args...); // 线…...
Windows版Apache 2.4.59解压直用(免安装-绿色-项目打包直接使用)
windows下Apache分类 Apache分为 安装版和解压版 安装版: 安装方便,下一步------下一步就OK了,但重装系统更换环境又要重新来一遍,会特别麻烦 解压版(推荐): 这种方式(项目打包特别方便&#x…...
刀具表面上的微结构
刀具表面微结构通常指在刀具表面对特定功能设计的微观纹理,这些纹理可以是沟槽、凹坑、凸起或任何其他形式的微观图案。这些微结构的设计和应用是为了改善刀具的切削性能,减少切削力和切削温度,提高切削效率和精度,同时降低切削液…...
css3实现微信扫码登陆动画
在做微信扫码登陆时,出现一个背景光图上下扫码动画,用css3图片实现。 实现原理: 1.准备一个渐变的背景.png图 2.css动画帧实现动画 看效果: css代码: #wx-scan{position: absolute;top:0px;left: 50%;z-index: 3;ma…...
vue3 导入excel数据
所需包 "xlsx": "^0.18.5"页面导入包 import * as XLSX from xlsx; import {genFileId, UploadProps, UploadRawFile,ElTable } from element-plus;页面 <el-upload accept".xlsx" :on-change"changeExcel" :on-exceed"ha…...
C# linq 根据多字段动态Group by
实现类: public static class LinqHepler {/// <summary>/// 根据单个字段动态Group/// </summary>/// <typeparam name"T"></typeparam>/// <param name"source"></param>/// <param name"prop…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...
