mybatis 中对元数据的操作

mybatis 中对元数据的操作




背景

在目前流行的持久层框架mybatis中,有些场景下需要获取数据库表的元数据(字段名称、字段类型、字段长度、字段注释等)操作,可以实现让繁琐的事情简单化,自动生成Javabean或者mybatis中的mapper.xml文件等等。

mybatis框架的逆向工程(mybatis-generate)也可以实现部分功能,有些场景是需要在Java运行时去动态获取字段列表等。


本篇文章在spring boot+mybatis架构下完成的,若是需要可以查看往期文章:

《Spring boot整合持久层框架Mybatis》


准备环节

在数据库 test 下建一张表 user

建表:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `username` varchar(255) DEFAULT NULL COMMENT '用户姓名',
  `password` varchar(255) DEFAULT NULL COMMENT '用户密码',
  `isadmin` int(1) DEFAULT NULL COMMENT '是否是管理员',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

字段:
user表字段


1. 使用MySQL内部数据库information_schema表查询实现


通过查询试图,读取表的字段等信息


1.1 MySQL内部字段表 information_schema.COLUMNS


MySQL中,存放表字段的内部表是:information_schema.COLUMNS

在这里插入图片描述


1.2 mybatis的mapper.xml文件



例如:查询数据库 test 下的 表 user 的 表字段列名等信息,在mapper.xml文件中

   
<select id="getUserTableColumns" resultType="map">
    SELECT 
    	* 
    FROM 
    	information_schema.COLUMNS 
    WHERE 
    	TABLE_SCHEMA = 'test' 
    AND 
    	TABLE_NAME = 'user'
</select>
    

TABLE_SCHEMA:数据库名称

TABLE_NAME:表名


mapper.java

@Mapper
public interface IUserMapper {
	
	public List<Map<String, Object>> getUserTableColumns();

}

1.3 mybatis服务层


/**
* @description
*	获取 元 数据
* @author TianwYam
* @date 2021年10月6日上午9:05:47
* @return
*/
public List<Map<String, Object>> getUserTableColumns(){
	return userMapper.getUserTableColumns();
}

1.4 输出结果

[
	{
		"TABLE_CATALOG":"def",
		"IS_NULLABLE":"NO",
		"TABLE_NAME":"user",
		"TABLE_SCHEMA":"test",
		"EXTRA":"auto_increment",
		"COLUMN_NAME":"id",
		"COLUMN_KEY":"PRI",
		"NUMERIC_PRECISION":10,
		"PRIVILEGES":"select,insert,update,references",
		"COLUMN_COMMENT":"主键ID",
		"NUMERIC_SCALE":0,
		"COLUMN_TYPE":"int(11)",
		"ORDINAL_POSITION":1,
		"DATA_TYPE":"int"
	},
	{
		"TABLE_CATALOG":"def",
		"IS_NULLABLE":"YES",
		"TABLE_NAME":"user",
		"TABLE_SCHEMA":"test",
		"EXTRA":"",
		"COLUMN_NAME":"username",
		"COLUMN_KEY":"",
		"CHARACTER_OCTET_LENGTH":765,
		"PRIVILEGES":"select,insert,update,references",
		"COLUMN_COMMENT":"用户姓名",
		"COLLATION_NAME":"utf8_general_ci",
		"COLUMN_TYPE":"varchar(255)",
		"ORDINAL_POSITION":2,
		"CHARACTER_MAXIMUM_LENGTH":255,
		"DATA_TYPE":"varchar",
		"CHARACTER_SET_NAME":"utf8"
	},
	{
		"TABLE_CATALOG":"def",
		"IS_NULLABLE":"YES",
		"TABLE_NAME":"user",
		"TABLE_SCHEMA":"test",
		"EXTRA":"",
		"COLUMN_NAME":"password",
		"COLUMN_KEY":"",
		"CHARACTER_OCTET_LENGTH":765,
		"PRIVILEGES":"select,insert,update,references",
		"COLUMN_COMMENT":"用户密码",
		"COLLATION_NAME":"utf8_general_ci",
		"COLUMN_TYPE":"varchar(255)",
		"ORDINAL_POSITION":3,
		"CHARACTER_MAXIMUM_LENGTH":255,
		"DATA_TYPE":"varchar",
		"CHARACTER_SET_NAME":"utf8"
	},
	{
		"TABLE_CATALOG":"def",
		"IS_NULLABLE":"YES",
		"TABLE_NAME":"user",
		"TABLE_SCHEMA":"test",
		"EXTRA":"",
		"COLUMN_NAME":"isadmin",
		"COLUMN_KEY":"",
		"NUMERIC_PRECISION":10,
		"PRIVILEGES":"select,insert,update,references",
		"COLUMN_COMMENT":"是否是管理员",
		"NUMERIC_SCALE":0,
		"COLUMN_TYPE":"int(1)",
		"ORDINAL_POSITION":4,
		"DATA_TYPE":"int"
	}
]

2. 使用jdbc方式获取元数据


2.1 使用原生jdbc获取元数据


2.1.1 原生JDBC

/**
 * @description
 *	JDBC 获取元数据方式
 * @author TianwYam
 * @date 2021年10月6日上午10:39:46
 */
public class JdbcTest {
	
	
	public static void main(String[] args) throws Exception {
		
		// 1. 配置 数据库链接信息
		String driver="com.mysql.cj.jdbc.Driver";
		String url="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC";
		String username="root";
		String password="mysql";

		//2. 加载驱动
		Class.forName(driver);

		//3. 建立连接
		Connection connection= DriverManager.getConnection(url,username,password);
		
		//4. 获取元数据
		DatabaseMetaData metaData = connection.getMetaData();
		
		//5. 获取表的字段 列
		ResultSet resultSet = metaData.getColumns("test", null, "user", null);

		//6. 处理ResultSet
		while(resultSet.next()){
		    //处理resultSet
		}

		//7. 释放资源
	    resultSet.close();
	    connection.close();
	}

}

这儿是采用原生jdbc方式对元数据操作获取表的字段所有列,基本上都是以上几步


2.1.2 DatabaseMetaData.getColumns

// 获取表所有字段
DatabaseMetaData.getColumns(String catalog, 
						String schemaPattern, 
						String tableNamePattern, 
						String columnNamePattern) ;

// catalog 分类 -- 数据库名称
// schemaPattern 约束
// tableNamePattern 表名
// columnNamePattern 字段列名


getColumns 方法返回值有:

在这里插入图片描述


2.2 mybatis采用JDBC方式获取元数据


持久层框架不同,需要对第三步中的获取连接 connection有所改变


思路:Spring boot集成mybatis框架中,获取connection是从 SqlSessionFactory 中获取到 SqlSession,然后从 SqlSession 中获取到 Connection


2.2.1 mybatis服务层

新建类 封装表字段返回数据结构

/**
 * @description
 *	表 元数据 字段列信息
 * @author TianwYam
 * @date 2021年10月5日下午8:08:08
 */
@Data
@Builder
public class TableColumnBean {
	
	private String dbName ;
	
	private String tableName ;
	
	private String columnName ;
	
	private String autoIncrement ;
	
	private String generatedColumn  ;
	
	private String columnType ;
	
	private int columnLength ;
	
	private String columnRemark ;

}

service类

@Service
public class UserService {
	
    // 自动引入(前提是 搭建了spring boot+mybatis架构)
	@Autowired
	private SqlSessionFactory sqlSessionFactory ;
	
	
	/**
	 * @description
	 *	获取 user 表的 元数据 表结构
	 * @author TianwYam
	 * @date 2021年10月6日上午9:05:14
	 * @return
	 */
	public List<TableColumnBean> getUserMeta() {
		
		List<TableColumnBean> columnList = new ArrayList<>();
		try {
			// 获取连接、获取元数据
			DatabaseMetaData metaData = sqlSessionFactory.openSession()
				.getConnection()
				.getMetaData();

			// 获取 表字段
			ResultSet columns = metaData.getColumns("test", null, "user", null);
			
            // 对结果集 ResultSet 操作
			System.out.println("column: ");
			while(columns.next()){
				TableColumnBean columnBean = TableColumnBean.builder()
						.dbName(columns.getString("TABLE_CAT"))
						.tableName(columns.getString("TABLE_NAME"))
						.columnName(columns.getString("COLUMN_NAME"))
						.autoIncrement(columns.getString("IS_AUTOINCREMENT"))
						.generatedColumn(columns.getString("IS_GENERATEDCOLUMN"))
						.columnType(columns.getString("TYPE_NAME"))
						.columnLength(columns.getInt("COLUMN_SIZE"))
						.columnRemark(columns.getString("REMARKS"))
						.build();
				columnList.add(columnBean);
	        }
			
			System.out.println(JSON.toJSONString(columnList, true));
		
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return columnList;
	}	

}



2.2.2 结果
[
	{
		"autoIncrement":"YES",
		"columnLength":10,
		"columnName":"id",
		"columnRemark":"主键ID",
		"columnType":"INT",
		"dbName":"test",
		"generatedColumn":"NO",
		"tableName":"user"
	},
	{
		"autoIncrement":"NO",
		"columnLength":255,
		"columnName":"username",
		"columnRemark":"用户姓名",
		"columnType":"VARCHAR",
		"dbName":"test",
		"generatedColumn":"NO",
		"tableName":"user"
	},
	{
		"autoIncrement":"NO",
		"columnLength":255,
		"columnName":"password",
		"columnRemark":"用户密码",
		"columnType":"VARCHAR",
		"dbName":"test",
		"generatedColumn":"NO",
		"tableName":"user"
	},
	{
		"autoIncrement":"NO",
		"columnLength":10,
		"columnName":"isadmin",
		"columnRemark":"是否是管理员",
		"columnType":"INT",
		"dbName":"test",
		"generatedColumn":"NO",
		"tableName":"user"
	}
]

最核心的就是:


DatabaseMetaData metaData = sqlSessionFactory.openSession()
	.getConnection()
	.getMetaData();

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
数据库操作 —— MyBatis `server-dao`模块集成了`mybatis-generator`,使用它来自动生成MyBatis的dao层,除此之外也添加了两个generator插件: + **MySQL分页**:此脚手架未采用基于MyBatis拦截器的第三方分页插件,而是直接在生成的dao层添加`setLimit*`,使用它们即可在生成的sql直接添加`limit ?, ?`,这样做即简洁又易于理解。 + **MySQL注释**:将数据库元数据的comment插入自动生成的Model类,便于代码的阅读。 由于`mybatis-generator`插件依赖了另外一个模块`server-common`,因此在执行generator前需要安装这些依赖到本地仓库: ``` mvn install ``` 否则`mybatis-generator`会因为找不到`server-common`依赖而执行失败。 ## 权限控制 —— shiro `server-api`模块集成了shiro进行权限控制,参见`com.boilerplate.server.init.ShiroConfig`类。 对于纯粹的后端server而言,可能还需要自己实现一个生成错误json的filter来替换默认filter,因为默认filter会在权限验证失败时重定向至错误页面。 ## 日志处理 —— logback 无它,唯一需要配置的就是日志输出位置,此脚手架支持在SpringBoot配置日志输出位置,这种配置对开发测试阶段更加友好,避免了日志文件满天飞的情况。 ## 标准化发布 不再采用传统的tomcat发布,模仿\*nix的应用目录结构,即: + **bin**:应用控制入口 + **conf**:应用配置 + **logs**:日志输出 + **static**:一些静态资源 ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。
压力测试 服务器是学生服务器,就是腾讯那个10的服务器,在本地利用jmeter压测工具设置5000个线程、10000个请求时,首页的QPS为1024,而秒杀接口则为1678,可能服务器的问题,我感觉QPS不应该这么低。 <img src="https://github.com/suyeq/steamMall/blob/master/TestResult.png" width=350px height=200px> # 项目的运行 在数据库创建steam库,然后导入sql文件,修改相应的的配置,关于主从配置请自行百度啦,运行起项目,然后需要把`GameService`类以及`CommentService`类里面的`afterPropertiesSet`方法里面的代码注释掉,这是第一次启动加载缓存的代码。 # 架构以及详细实现 ## 1.登录注册 * 两次md5,对密码加密 * 分布式session,将用户的登录信息缓存在redis * 权限检查,每次操作在权限允许下才能进行 * 注册,需要邮箱验证码,邮箱验证码会在缓存存在90s的时间 ## 2.页面数据 * 首页及其他页面因为读多写少,利用Mysql主从复制实现读写分离,写入在主Mysql下进行,读取在从Mysql进行 * 关于数据的不一致性,可以在写入的时候先写入缓存,读取的时候也先在缓存读取,这样就可以避免数据的不一致性 * 缓存利用Redis,内存满的情况下,键的删除策略采用volatile-lru * 热卖榜以及排序功能依据Redis的zset实现,缓存时间为30s * 为了减少网络时延的影响,引入了redis的管道技术,实行批处理 * 为了更好地加快性能,在redis缓存层之上加了加了一层本地的缓存 ## 3.秒杀功能 原理:尽量减少Mysql的访问 * 将先将需要秒杀的数据缓存在Redis,在秒杀接口里做预减少库存 * 判断秒杀订单里有无对应的信息,有则秒杀重复 * 将user信息与秒杀资源信息加入消息队列 * 消息接受者减少库存,新增秒杀订单 * 客户端不断轮询缓存,查询到对应的秒杀订单,则秒杀成功<br> 秒杀的一些优化(借鉴了网上的思路): * 增加了秒杀的随机路径,防刷 * 在秒杀开始前需要验证码输入,延缓压力 * 利用redis的缓存,限制每个用户的每分钟的秒杀次数 ## 4.页面的渲染 * 页面的渲染采取了jquery加ajax技术的字符串拼接以及thymleaf模板的渲染 * 大部分是用的字符串拼接,只有少部分采用的模板渲染 * 前端主要是由字符串拼接,后台主要是模板渲染 ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天涯共明月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值