本文所有代码已上传至码云:https://gitee.com/rangers-sun/mybatis

  1. 修改IUserDao、UserMapper.xml

    package com.rangers;
    
    import com.rangers.entity.User;
    
    import java.util.List;
    
    /**
    * @Author Rangers
    * @Description 用户数据库访问Dao
    * @Date 2021-03-07
    **/
    public interface IUserDao { /**
    * @Author Rangers
    * @Description 查询所有用户信息
    * @Date 2021/3/7 10:43 上午
    * @Return: java.util.List<com.rangers.entity.User>
    **/
    public List<User> selectList(); /**
    * @Author Rangers
    * @Description 根据条件查询单个用户信息
    * @Date 2021/3/7 10:43 上午
    * @Param user:
    * @Return: com.rangers.entity.User
    **/
    public User selectOne(User user) ; Integer insert(User user); Integer update(User user); Integer delete(User user);
    }
    <mapper namespace="com.rangers.IUserDao">
    
        <select id="selectOne" parameterType="com.rangers.entity.User" resultType="com.rangers.entity.User">
    select * from user where id=#{id} and name=#{name}
    </select> <select id="selectList" parameterType="com.rangers.entity.User" resultType="com.rangers.entity.User">
    select * from user
    </select> <insert id="insert" parameterType="com.rangers.entity.User" resultType="java.lang.Integer">
    insert into user(id,name,address) values(#{id},#{name},#{address})
    </insert> <update id="update" parameterType="com.rangers.entity.User" resultType="java.lang.Integer">
    update user set name=#{name},address=#{address} where id=#{id}
    </update> <delete id="delete" parameterType="com.rangers.entity.User" resultType="java.lang.Integer">
    delete from user where id=#{id}
    </delete>
    </mapper>
  2. 新增SqlCommondType 修改MappedStatement、XmlMapperBuilder

    package com.rangers.persistent.config;
    
    /**
    * @Author Rangers
    * @Description
    * @Date 2021-03-08
    **/
    public enum SqlCommondType { INSERT, DELETE, UPDATE, SELECT;
    }
    package com.rangers.persistent.config.pojo;
    
    import com.rangers.persistent.config.SqlCommondType;
    
    /**
    * @Author Rangers
    * @Description 对应Mapper中标签的信息
    * @Date 2021-03-04
    **/
    public class MappedStatement {
    // id当前xml中的唯一标识
    private String id; // sql语句
    private String sql; // 参数类型
    private String paramterType; // 返回结果类型
    private String resultType; // 返回结果类型
    private SqlCommondType sqlCommondType; public String getId() {
    return id;
    } public void setId(String id) {
    this.id = id;
    } public String getSql() {
    return sql;
    } public void setSql(String sql) {
    this.sql = sql;
    } public String getParamterType() {
    return paramterType;
    } public void setParamterType(String paramterType) {
    this.paramterType = paramterType;
    } public String getResultType() {
    return resultType;
    } public void setResultType(String resultType) {
    this.resultType = resultType;
    } public SqlCommondType getSqlCommondType() {
    return sqlCommondType;
    } public void setSqlCommondType(SqlCommondType sqlCommondType) {
    this.sqlCommondType = sqlCommondType;
    }
    }
    package com.rangers.persistent.config;
    
    import com.rangers.persistent.config.pojo.Configuration;
    import com.rangers.persistent.config.pojo.MappedStatement;
    import org.apache.commons.collections.CollectionUtils;
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader; import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.List; /**
    * @Author Rangers
    * @Description 解析XxMapper.xml
    * @Date 2021-03-04
    **/
    public class XmlMapperBuilder {
    private Configuration configuration; public XmlMapperBuilder(Configuration configuration) {
    this.configuration = configuration;
    } public void parse(InputStream inputStream) {
    Document document = null;
    try {
    document = new SAXReader().read(inputStream);
    } catch (DocumentException e) {
    e.printStackTrace();
    }
    Element rootElement = document.getRootElement(); String namespace = rootElement.attributeValue("namespace"); List<Element> elements = new ArrayList<>();
    List<Element> selectElements = rootElement.selectNodes("//select");
    elements.addAll(selectElements);
    List<Element> insertElements = rootElement.selectNodes("//insert");
    elements.addAll(insertElements);
    List<Element> updateElements = rootElement.selectNodes("//update");
    elements.addAll(updateElements);
    List<Element> deleteElements = rootElement.selectNodes("//delete");
    elements.addAll(deleteElements);
    // 解析XxMapper.xml中的标签
    this.parseLabel(namespace, elements);
    } private void parseLabel(String namespace, List<Element> selectElements) {
    if (CollectionUtils.isNotEmpty(selectElements)){
    selectElements.forEach(mapperElement->{
    String id = mapperElement.attributeValue("id");
    String sql = mapperElement.getTextTrim();
    String parameterType = mapperElement.attributeValue("parameterType");
    String resultType = mapperElement.attributeValue("resultType");
    String sqlCommondType = mapperElement.getName(); MappedStatement mappedStatement = new MappedStatement();
    mappedStatement.setId(id);
    mappedStatement.setSql(sql);
    mappedStatement.setParamterType(parameterType);
    mappedStatement.setResultType(resultType);
    mappedStatement.setSqlCommondType(SqlCommondType.valueOf(sqlCommondType.toUpperCase()));
    configuration.getMappedStatementMap().put(namespace +"."+id,mappedStatement);
    });
    }
    } }
  3. 修改SqlSession、DefaultSqlSession

    package com.rangers.persistent.sqlSession;
    
    import java.sql.SQLException;
    import java.util.List; /**
    * @Author Rangers
    * @Description
    * @Date 2021-03-04
    **/
    public interface SqlSession { <E> List<E> selectList(String statementId,Object...param) throws Exception; <T> T selectOne(String statementId,Object...param) throws Exception; Integer insert(String statementId,Object...param) throws Exception; Integer update(String statementId,Object...param) throws Exception; Integer delete(String statementId,Object...param) throws Exception; void close() throws SQLException; <T> T getMapper(Class<T> t);
    }
    package com.rangers.persistent.sqlSession;
    
    import com.rangers.persistent.config.SqlCommondType;
    import com.rangers.persistent.config.pojo.Configuration;
    import com.rangers.persistent.config.pojo.MappedStatement;
    import com.rangers.persistent.executor.Executor;
    import com.rangers.persistent.executor.SimpleExecutor;
    import org.apache.commons.collections.CollectionUtils; import java.lang.reflect.*;
    import java.sql.SQLException;
    import java.util.List; /**
    * @Author Rangers
    * @Description
    * @Date 2021-03-04
    **/
    public class DefaultSqlSession implements SqlSession{ private Configuration configuration; public DefaultSqlSession(Configuration configuration) {
    this.configuration = configuration;
    } private Executor executor = new SimpleExecutor(); @Override
    public <E> List<E> selectList(String statementId, Object... params) throws Exception {
    MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
    return executor.query(configuration,mappedStatement,params);
    } @Override
    public <T> T selectOne(String statementId, Object... params) throws Exception {
    List<Object> objects = this.selectList(statementId, params);
    if (CollectionUtils.isNotEmpty(objects)){
    if (objects.size() == 1){
    return (T) objects.get(0);
    }else {
    throw new Exception("返回多条记录");
    }
    }
    return null;
    } @Override
    public Integer insert(String statementId, Object... param) throws Exception {
    MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
    return executor.insert(configuration,mappedStatement,param);
    } @Override
    public Integer update(String statementId, Object... param) throws Exception {
    MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
    return executor.update(configuration,mappedStatement,param);
    } @Override
    public Integer delete(String statementId, Object... param) throws Exception {
    MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
    return executor.delete(configuration,mappedStatement,param);
    } @Override
    public void close() throws SQLException {
    executor.close();
    } /**
    * @Author Rangers
    * @Description 使用JDK动态代理获取执行的Mapper对象
    **/
    @Override
    public <T> T getMapper(Class<T> t) {
    Object o = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{t}, new InvocationHandler() {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 全限定性类名==XxMapper.xml的namespace
    String className = method.getDeclaringClass().getName();
    // 接口的方法名称==XxMapper.xml的每个mapper标签的id
    String methodName = method.getName(); // 1、构造statementID:namespace+"."+id
    String statementId = className+"."+methodName; // 2、定位方法执行,获取执行结果
    Object result = new Object();
    MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
    SqlCommondType sqlCommondType = mappedStatement.getSqlCommondType();
    switch (sqlCommondType){
    case INSERT:
    result = insert(statementId,args);
    break;
    case DELETE:
    result = delete(statementId,args);
    break;
    case UPDATE:
    result = update(statementId,args);
    break;
    case SELECT:
    // 获取被调用方法的返回值
    Type returnType = method.getGenericReturnType();
    if (returnType instanceof ParameterizedType){
    result = selectList(statementId, args);
    }else{
    result = selectOne(statementId,args);
    }
    break;
    default:
    throw new Exception("statementId:"+statementId+",操作类型:"+sqlCommondType+"有误");
    }
    return result;
    }
    });
    return (T) o;
    }
    }
  4. 修改Executor、SimpleExecutor

  5. package com.rangers.persistent.executor;
    
    import com.rangers.persistent.config.pojo.Configuration;
    import com.rangers.persistent.config.pojo.MappedStatement; import java.sql.SQLException;
    import java.util.List; /**
    * @Author Rangers
    * @Description
    * @Date 2021-03-04
    **/
    public interface Executor { <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object...param) throws Exception; Integer insert(Configuration configuration, MappedStatement mappedStatement, Object...param) throws Exception; Integer update(Configuration configuration, MappedStatement mappedStatement, Object...param) throws Exception; Integer delete(Configuration configuration, MappedStatement mappedStatement, Object...param) throws Exception; void close() throws SQLException;
    }
    package com.rangers.persistent.executor;
    
    import com.mchange.v2.c3p0.impl.NewProxyPreparedStatement;
    import com.rangers.persistent.config.pojo.Configuration;
    import com.rangers.persistent.config.pojo.MappedStatement;
    import com.rangers.persistent.utils.GenericTokenParser;
    import com.rangers.persistent.utils.ParameterMapping;
    import com.rangers.persistent.utils.ParameterMappingTokenHandler;
    import org.apache.commons.collections.CollectionUtils; import java.beans.PropertyDescriptor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List; /**
    * @Author Rangers
    * @Description
    * @Date 2021-03-04
    **/
    public class SimpleExecutor implements Executor { private Connection connnection = null; @Override
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
    PreparedStatement preparedStatement = this.getPreparedStatement(configuration, mappedStatement, params); // 5、执行SQL语句
    ResultSet resultSet = preparedStatement.executeQuery(); // 6、封装返回结果集
    // 获取SQL的执行结果类型
    String resultType = mappedStatement.getResultType();
    Class<?> resultTypeClazz = getClassType(resultType);
    List<E> results = new ArrayList<>();
    // 遍历封装结果集为返回值类型
    while (resultSet.next()) {
    // 获取结果集的元数据
    ResultSetMetaData metaData = resultSet.getMetaData();
    E e = (E) resultTypeClazz.newInstance();
    if (metaData.getColumnCount() > 0) {
    for (int i = 1; i <= metaData.getColumnCount(); i++) {
    // 字段名称
    String columnName = metaData.getColumnName(i);
    // 字段值
    Object columnValue = resultSet.getObject(columnName); // 使用反射或者内省,根据数据库表与实体的对应关系,完成结果集封装
    PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName,resultTypeClazz);
    Method writeMethod = propertyDescriptor.getWriteMethod();
    writeMethod.invoke(e,columnValue);
    }
    }
    results.add(e);
    }
    return results;
    } @Override
    public Integer insert(Configuration configuration, MappedStatement mappedStatement, Object... param) throws Exception {
    return this.update(configuration,mappedStatement,param);
    } @Override
    public Integer update(Configuration configuration, MappedStatement mappedStatement, Object... param) throws Exception {
    PreparedStatement preparedStatement = this.getPreparedStatement(configuration, mappedStatement, param);
    return preparedStatement.executeUpdate();
    } @Override
    public Integer delete(Configuration configuration, MappedStatement mappedStatement, Object... param) throws Exception {
    return this.update(configuration,mappedStatement,param);
    } private PreparedStatement getPreparedStatement(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
    // 1、获取数据库链接
    connnection = configuration.getDataSource().getConnection();
    // 2、解析SQL语句中的#/$,及参数列表,封装为BoundSql对象
    BoundSql boundSql = getBoundSQL(mappedStatement.getSql());
    // 替换后的SQL语句
    String finalSql = boundSql.getSqlText();
    // 3、获取PreparedStatement对象
    PreparedStatement preparedStatement = connnection.prepareStatement(finalSql); // 4、设置参数
    // 获取传入参数类型
    String parameterType = mappedStatement.getParamterType();
    Class<?> parameterTypeClazz = getClassType(parameterType);
    // 获取SQL语句中需要替换的的参数列表
    List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
    if (CollectionUtils.isNotEmpty(parameterMappingList)) {
    for (int i = 0; i < parameterMappingList.size(); i++) {
    ParameterMapping parameterMapping = parameterMappingList.get(i);
    // SQL语句中解析出的占位参数名称
    String content = parameterMapping.getContent(); // 利用反射从入参列表中获取数据
    Field declaredField = parameterTypeClazz.getDeclaredField(content);
    // 设置暴力访问
    declaredField.setAccessible(true);
    // 此处默认传入参数类型为对象
    Object param = declaredField.get(params[0]);
    preparedStatement.setObject(i + 1, param);
    }
    }
    // 打印执行语句
    this.printSql(preparedStatement); return preparedStatement;
    } private void printSql(PreparedStatement preparedStatement) throws NoSuchFieldException, IllegalAccessException {
    NewProxyPreparedStatement tmpPs = (NewProxyPreparedStatement) preparedStatement;
    Field inner = preparedStatement.getClass().getDeclaredField("inner");
    inner.setAccessible(true);
    String sqlLog = inner.get(tmpPs).toString();
    System.out.println("执行SQL:"+sqlLog.substring(sqlLog.lastIndexOf(":")+1));
    } private Class<?> getClassType(String type) throws ClassNotFoundException {
    if (type != null && type!="") {
    return Class.forName(type);
    }
    return null;
    } private BoundSql getBoundSQL(String sql) {
    ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
    GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
    String parseSql = genericTokenParser.parse(sql);
    List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
    return new BoundSql(parseSql, parameterMappings);
    } @Override
    public void close() throws SQLException {
    connnection.close();
    }
    }
  6. 拆分测试类直接获取与动态代理

    package com.rangers.mypersistent;
    
    import com.rangers.entity.User;
    import com.rangers.persistent.sqlSession.SqlSession;
    import com.rangers.persistent.sqlSessionFactory.SqlSessionFactory;
    import com.rangers.persistent.sqlSessionFactory.SqlSessionFactoryBuilder;
    import com.rangers.persistent.utils.Resources;
    import org.dom4j.DocumentException;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test; import java.beans.PropertyVetoException;
    import java.io.InputStream;
    import java.sql.SQLException;
    import java.util.List; /**
    * @Author Rangers
    * @Description
    * @Date 2021-03-04
    **/
    public class MyPersistentTest { private SqlSession sqlSession; @Before
    public void before() throws PropertyVetoException, DocumentException {
    // 加载配置文件
    InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
    // 解析XML文件为对象,构造SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    sqlSession = sqlSessionFactory.openSession();
    } @Test
    public void selectList() throws Exception {
    List<User> users = sqlSession.selectList("com.rangers.IUserDao.selectList", null);
    System.out.println(users.toString());;
    } @Test
    public void selectOne() throws Exception {
    User user = new User();
    user.setId(2);
    user.setName("莉莉");
    User result = sqlSession.selectOne("com.rangers.IUserDao.selectOne", user);
    System.out.println(result.toString());
    } @Test
    public void insert() throws Exception {
    User user = new User();
    user.setId(3);
    user.setName("bug");
    user.setAddress("北京");
    boolean insertFlag = sqlSession.insert("com.rangers.IUserDao.insert",user) > 0;
    System.out.println("新增标识:"+insertFlag);
    } @Test
    public void update() throws Exception {
    User user = new User();
    user.setId(3);
    user.setName("虫子");
    user.setAddress("北京");
    boolean updateFlag = sqlSession.update("com.rangers.IUserDao.update", user)>0;
    System.out.println("修改标识:"+updateFlag);
    } @Test
    public void delete() throws Exception {
    User user = new User();
    user.setId(3);
    boolean updateFlag = sqlSession.update("com.rangers.IUserDao.delete", user)>0;
    System.out.println("删除标识:"+updateFlag);
    } @After
    public void after() throws SQLException {
    sqlSession.close();
    }
    }
    package com.rangers.mypersistent;
    
    import com.rangers.IUserDao;
    import com.rangers.entity.User;
    import com.rangers.persistent.sqlSession.SqlSession;
    import com.rangers.persistent.sqlSessionFactory.SqlSessionFactory;
    import com.rangers.persistent.sqlSessionFactory.SqlSessionFactoryBuilder;
    import com.rangers.persistent.utils.Resources;
    import org.dom4j.DocumentException;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test; import java.beans.PropertyVetoException;
    import java.io.InputStream;
    import java.sql.SQLException;
    import java.util.List; /**
    * @Author Rangers
    * @Description
    * @Date 2021-03-08
    **/
    public class MapperTest { private SqlSession sqlSession; @Before
    public void before() throws PropertyVetoException, DocumentException {
    // 加载配置文件
    InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
    // 解析XML文件为对象,构造SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    sqlSession = sqlSessionFactory.openSession();
    } @Test
    public void mapperSelectOne() throws Exception {
    User userParam = new User();
    userParam.setId(2);
    userParam.setName("莉莉");
    IUserDao userDao = sqlSession.getMapper(IUserDao.class);
    User result = userDao.selectOne(userParam);
    System.out.println(result.toString());
    } @Test
    public void mapperSelectAll() throws Exception {
    IUserDao userDao = sqlSession.getMapper(IUserDao.class);
    List<User> result = userDao.selectList();
    System.out.println(result.toString());
    } @Test
    public void mapperInsert() throws Exception {
    IUserDao userDao = sqlSession.getMapper(IUserDao.class);
    User user = new User();
    user.setId(3);
    user.setName("bug");
    user.setAddress("北京");
    boolean insertFlag = userDao.insert(user) > 0;
    System.out.println("新增标识:"+insertFlag);
    } @Test
    public void mapperUpdate() throws Exception {
    IUserDao userDao = sqlSession.getMapper(IUserDao.class);
    User user = new User();
    user.setId(3);
    user.setName("虫子");
    user.setAddress("北京");
    boolean updateFlag = userDao.update(user) > 0;
    System.out.println("修改标识:"+updateFlag);
    } @Test
    public void mapperDelete() throws Exception {
    IUserDao userDao = sqlSession.getMapper(IUserDao.class);
    User user = new User();
    user.setId(3);
    boolean deleteFlag = userDao.delete(user) > 0;
    System.out.println("删除标识:"+deleteFlag);
    } @After
    public void after() throws SQLException {
    sqlSession.close();
    }
    }

MyBatis(四):自定义持久层框架优化的更多相关文章

  1. Mybatis学习之自定义持久层框架(七) 自定义持久层框架优化

    前言 接上文,这里只是出于强迫症,凭借着半年前的笔记来把之前没写完的文章写完,这里是最后一篇了. 前面自定义的持久层框架存在的问题 Dao层若使用实现类,会存在代码重复,整个操作的过程模版重复(加载配 ...

  2. MyBatis(三):自定义持久层框架实现

    代码已上传至码云:https://gitee.com/rangers-sun/mybatis 新建Maven工程 架构端MyPersistent.使用端MyPersistentTest,使用端引入架构 ...

  3. MyBatis(二):自定义持久层框架思路分析

    使用端 引入架构端Maven依赖 SqlMapConfig.xml-数据库配置信息(数据库连接jar名称.连接URL.用户名.密码),引入Mapper.xml的路径 XxMapper.xml-SQL配 ...

  4. Java工程师高薪训练营-第一阶段 开源框架源码解析-模块一 持久层框架涉及实现及MyBatis源码分析-任务一:自定义持久层框架

    目录 任务一:自定义持久层框架 1.1 JDBC回顾及问题分析 1.2 自定义持久层框架思路分析 1.3 IPersistence_Test编写 1.3.1 XXXMapper.xml详解 1.3.2 ...

  5. 【笔记】拉勾Java工程师高薪训练营-第一阶段 开源框架源码解析-模块一 持久层框架涉及实现及MyBatis源码分析-任务一:自定义持久层框架

    以下笔记是我看完视频之后总结整理的,部分较为基础的知识点也做了补充,如有问题欢迎沟通. 目录 任务一:自定义持久层框架 1.1 JDBC回顾及问题分析 1.2 自定义持久层框架思路分析 1.3 IPe ...

  6. Mybatis学习之自定义持久层框架(三) 自定义持久层框架:读取并解析配置文件

    前言 前两篇文章分别讲解了JDBC和Mybatis的基本知识,以及自定义持久层框架的设计思路,从这篇文章开始,我们正式来实现一个持久层框架. 新建一个项目 首先我们新建一个maven项目,将其命名为I ...

  7. Mybatis学习之自定义持久层框架(二) 自定义持久层框架设计思路

    前言 上一篇文章讲到了JDBC的基本用法及其问题所在,并提出了使用Mybatis的好处,那么今天这篇文章就来说一下该如何设计一个类似Mybatis这样的持久层框架(暂时只讲思路,具体的代码编写工作从下 ...

  8. Mybatis学习之自定义持久层框架(六) 自定义持久层框架:完善CRUD方法并进行测试

    前言 没想到会等到半年以后才来写这篇文章,我已经不记得当初自己想要在这篇文章中写什么了,还好有一些零散的笔记留着,就对照着上一篇文章及零散的笔记,把内容给补充完吧. 完善CRUD方法 完善Defaul ...

  9. Mybatis学习之自定义持久层框架(一) 为什么要用框架而不直接用JDBC?

    前言 说起Mybatis,相信大家都不会感到陌生,它是一款优秀的持久层框架,应用于java后端开发中,为客户端程序提供访问数据库的接口. 我们都知道,JDBC是Java语言中用来规范客户端程序如何来访 ...

随机推荐

  1. vs2019激活码

    Visual Studio 2019 Enterprise BF8Y8-GN2QH-T84XB-QVY3B-RC4DF Visual Studio 2019 Professional NYWVH-HT ...

  2. Vulkan与DX11交互

    Demo演示地址07_wintest 有什么用 在android平台主流是用opengl es,android下vulkan与opengles纹理互通. 而在win平台,主流游戏还用的是DX11,如果 ...

  3. 根据直方图 histogram 进行简单的图像检索

    https://github.com/TouwaErioH/Machine-Learning/tree/master/image%20identification/Histogram%20retrie ...

  4. Pymongo 笔记

    Pymongo 1.MongoDB概念 MongoDB是一种非关系型数据库(NoSQL),MongoDB数据存储于内存,内存不足则将热度低数据写回磁盘.存储的数据结构为文档.每个数据库包含若干集合(c ...

  5. HDU 3949 XOR (线性基第k小)题解

    题意: 给出\(n\)个数,求出子集异或第\(k\)小的值,不存在输出-1. 思路: 先用线性基存所有的子集,然后对线性基每一位进行消元,保证只有\(d[i]\)的\(i\)位存在1,那么这样变成了一 ...

  6. 谈一谈phar 反序列化

    前言 来自Secarma的安全研究员Sam Thomas发现了一种新的漏洞利用方式,可以在不使用php函数unserialize()的前提下,引起严重的php对象注入漏洞.这个新的攻击方式被他公开在了 ...

  7. vue2 响应式细节

    data 中的数据是如何处理的? 每一次实例化一个组件,都会调用 initData 然后调用 observe 方法,observe 方法调用了 new Observer(value), 并且返回 __ ...

  8. ossutilmac64

    ossutilmac64 ossutil是以命令行方式管理OSS数据的工具,提供方便.简洁.丰富的存储空间(Bucket)和文件(Object)管理命令,支持Windows.Linux. Mac平台. ...

  9. Linux in depth

    Linux in depth bash file text editor filter selector command ?

  10. PWA & TWA

    PWA & TWA https://www.bilibili.com/video/av68082979/ Service Worker workbox.js https://developer ...