Mybatis源码阅读(五 ):接口层——SqlSession

*************************************优雅的分割线 **********************************

分享一波:程序员赚外快-必看的巅峰干货

如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程

请关注微信公众号:HB荷包
在这里插入图片描述
一个能让你学习技术和赚钱方法的公众号,持续更新
*************************************优雅的分割线 **********************************
SimpleExecutor
SqlSession

SqlSession是Mybatis的核心接口之一,对外提供常用的数据库操作api。mybatis提供了两个SqlSession的实现,其中最常用的是DefaultSqlSession。

SqlSession的代码如下

/**

  • 接口层,也是开发人员使用mybatis去操作sql所使用的主要的接口

  • @author Clinton Begin
    */
    public interface SqlSession extends Closeable {

    /**

    • 查询sql单条数据
    • @param 返回的数据类型
    • @param statement sql
    • @return Mapped object
      */
      T selectOne(String statement);

    /**

    • 指定sql并传入实参去查单条数据
    • @param 返回的数据类型
    • @param statement 预编译的带有?的sql
    • @param parameter 用户传入的实参,与前面sql绑定
    • @return Mapped object
      */
      T selectOne(String statement, Object parameter);

    /**

    • 执行sql查询多条数据
    • @param 返回的数据类型
    • @param statement sql
    • @return List of mapped object
      */
      List selectList(String statement);

    /**

    • 指定sql并传入实参去查多条数据
    • @param 返回的数据类型
    • @param statement 预编译的带有问号的sql
    • @param parameter 用户传入的实参,与前面的sql绑定
    • @return List of mapped object
      */
      List selectList(String statement, Object parameter);

    /**

    • 使用预编译的sql,指定传入的实参以及结果集范围
    • 查询指定范围的所有数据
    • @param 返回的数据类型
    • @param statement 预编译的带有问号的sql
    • @param parameter 用户传入的实参,与前面的sql绑定
    • @param rowBounds 指定查询范围
    • @return List of mapped object
      */
      List selectList(String statement, Object parameter, RowBounds rowBounds);

    /**

    • 执行sql,返回map对象
    • @param the returned Map keys type
    • @param the returned Map values type
    • @param statement Unique identifier matching the statement to use.
    • @param mapKey The property to use as key for each value in the list.
    • @return Map containing key pair data.
      */
      <K, V> Map<K, V> selectMap(String statement, String mapKey);

    /**

    • 指定sql和实参,返回map
    • @param the returned Map keys type
    • @param the returned Map values type
    • @param statement Unique identifier matching the statement to use.
    • @param parameter A parameter object to pass to the statement.
    • @param mapKey The property to use as key for each value in the list.
    • @return Map containing key pair data.
      */
      <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);

    /**

    • 指定sql、实参、范围,返回map
    • @param the returned Map keys type
    • @param the returned Map values type
    • @param statement Unique identifier matching the statement to use.
    • @param parameter A parameter object to pass to the statement.
    • @param mapKey The property to use as key for each value in the list.
    • @param rowBounds Bounds to limit object retrieval
    • @return Map containing key pair data.
      */
      <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);

    /**

    • A Cursor offers the same results as a List, except it fetches data lazily using an Iterator.
    • @param the returned cursor element type.
    • @param statement Unique identifier matching the statement to use.
    • @return Cursor of mapped objects
      */
      Cursor selectCursor(String statement);

    /**

    • A Cursor offers the same results as a List, except it fetches data lazily using an Iterator.
    • @param the returned cursor element type.
    • @param statement Unique identifier matching the statement to use.
    • @param parameter A parameter object to pass to the statement.
    • @return Cursor of mapped objects
      */
      Cursor selectCursor(String statement, Object parameter);

    /**

    • A Cursor offers the same results as a List, except it fetches data lazily using an Iterator.
    • @param the returned cursor element type.
    • @param statement Unique identifier matching the statement to use.
    • @param parameter A parameter object to pass to the statement.
    • @param rowBounds Bounds to limit object retrieval
    • @return Cursor of mapped objects
      */
      Cursor selectCursor(String statement, Object parameter, RowBounds rowBounds);

    /**

    • 将查询结果通过此处的ResultHandler对象封装成对应的对象
    • @param statement Unique identifier matching the statement to use.
    • @param parameter A parameter object to pass to the statement.
    • @param handler ResultHandler that will handle each retrieved row
      */
      void select(String statement, Object parameter, ResultHandler handler);

    /**

    • Retrieve a single row mapped from the statement
    • using a {@code ResultHandler}.
    • @param statement Unique identifier matching the statement to use.
    • @param handler ResultHandler that will handle each retrieved row
      */
      void select(String statement, ResultHandler handler);

    /**

    • Retrieve a single row mapped from the statement key and parameter
    • using a {@code ResultHandler} and {@code RowBounds}.
    • @param statement Unique identifier matching the statement to use.
    • @param rowBounds RowBound instance to limit the query results
    • @param handler ResultHandler that will handle each retrieved row
      */
      void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);

    /**

    • 执行insert
    • @param statement Unique identifier matching the statement to execute.
    • @return int The number of rows affected by the insert.
      */
      int insert(String statement);

    /**

    • Execute an insert statement with the given parameter object. Any generated
    • autoincrement values or selectKey entries will modify the given parameter
    • object properties. Only the number of rows affected will be returned.
    • @param statement Unique identifier matching the statement to execute.
    • @param parameter A parameter object to pass to the statement.
    • @return int The number of rows affected by the insert.
      */
      int insert(String statement, Object parameter);

    /**

    • 执行update
    • @param statement Unique identifier matching the statement to execute.
    • @return int The number of rows affected by the update.
      */
      int update(String statement);

    /**

    • Execute an update statement. The number of rows affected will be returned.
    • @param statement Unique identifier matching the statement to execute.
    • @param parameter A parameter object to pass to the statement.
    • @return int The number of rows affected by the update.
      */
      int update(String statement, Object parameter);

    /**

    • 执行delete
    • @param statement Unique identifier matching the statement to execute.
    • @return int The number of rows affected by the delete.
      */
      int delete(String statement);

    /**

    • Execute a delete statement. The number of rows affected will be returned.
    • @param statement Unique identifier matching the statement to execute.
    • @param parameter A parameter object to pass to the statement.
    • @return int The number of rows affected by the delete.
      */
      int delete(String statement, Object parameter);

    /**

    • 提交事务
      */
      void commit();

    /**

    • Flushes batch statements and commits database connection.
    • @param force forces connection commit
      */
      void commit(boolean force);

    /**

    • 回滚事务
      */
      void rollback();

    /**

    • Discards pending batch statements and rolls database connection back.
    • Note that database connection will not be rolled back if no updates/deletes/inserts were called.
    • @param force forces connection rollback
      */
      void rollback(boolean force);

    /**

    • 将请求刷新到数据库
    • @return BatchResult list of updated records
    • @since 3.0.6
      */
      List flushStatements();

    /**

    • 关闭SqlSession
      */
      @Override
      void close();

    /**

    • 清空 缓存
      */
      void clearCache();

    /**

    • Retrieves current configuration.
    • @return Configuration
      */
      Configuration getConfiguration();

    /**

    • 使用type获取对应的Mapper
    • @param the mapper type
    • @param type Mapper interface class
    • @return a mapper bound to this SqlSession
      */
      T getMapper(Class type);

    /**

    • 获取该SqlSession对应的数据库连接
    • @return Connection
      */
      Connection getConnection();
      }

DefaultSqlSession

在mybatis单独使用的时候,DefaultSqlSession是最常使用的SqlSession实现。DefaultSqlSession核心字段如下,其中已经过多介绍的类将不再注释。

private final Configuration configuration;
private final Executor executor;/*** 是否自动提交事务*/
private final boolean autoCommit;/*** 当前缓存是否有脏数据*/
private boolean dirty;

DefaultSqlSession中使用到了策略模式(不知道策略模式的请看我以前的帖子)。DefaultSqlSession扮演了上下文,只是通过executor字段的不同,而选择不同的Executor去操作数据库。

DefaultSqlSession为每种SQL操作都提供了大量的重载,对于不同的参数都提供了一个重载方法, 便于开发者去调用。这里只贴出核心的方法,对于重载方法将不进行介绍。

 * 根据sql和实参查询一条数据* @param statement 预编译的带有?的sql* @param parameter 用户传入的实参,与前面sql绑定* @param <T>* @return*/
@Override
public <T> T selectOne(String statement, Object parameter) {// 调用selectList查询多条List<T> list = this.selectList(statement, parameter);// 如果查询到的数据长度1是或者0就正常,否则抛出异常if (list.size() == 1) {return list.get(0);} else if (list.size() > 1) {// 这里的异常信息是不是很熟悉呢throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());} else {return null;}
}/*** 查询结果封装成map返回* 阅读源码发现,这里的selectMap貌似并不是将结果集按照属性映射成map* 而是把map当做list去使用。* 查询出多条数据,使用不同的key去封装到map* 这里的V应该是这一条数据映射的对象,或者是Map<String, Object>* @param statement Unique identifier matching the statement to use.* @param parameter A parameter object to pass to the statement.* @param mapKey    The property to use as key for each value in the list.* @param rowBounds Bounds to limit object retrieval* @param <K>* @param <V>* @return*/
@Override
public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {// 查询列表final List<? extends V> list = selectList(statement, parameter, rowBounds);// 创建Map返回集处理器final DefaultMapResultHandler<K, V> mapResultHandler = new DefaultMapResultHandler<>(mapKey,configuration.getObjectFactory(), configuration.getObjectWrapperFactory(), configuration.getReflectorFactory());final DefaultResultContext<V> context = new DefaultResultContext<>();for (V o : list) {// 暂存一下当前结果对象context.nextResultObject(o);// 处理上下文中的结果对象mapResultHandler.handleResult(context);}// 将map返回回去return mapResultHandler.getMappedResults();
}/*** 根据传入的sql、实参、查询范围去查询一个列表* @param statement 预编译的带有问号的sql* @param parameter 用户传入的实参,与前面的sql绑定* @param rowBounds 指定查询范围* @param <E>* @return*/
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {try {MappedStatement ms = configuration.getMappedStatement(statement);return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);} catch (Exception e) {throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}
}/*** 根据sql、实参、范围查询* 将查询结果交给指定的ResultHandler去处理* @param statement Unique identifier matching the statement to use.* @param parameter* @param rowBounds RowBound instance to limit the query results* @param handler   ResultHandler that will handle each retrieved row*/
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {try {MappedStatement ms = configuration.getMappedStatement(statement);executor.query(ms, wrapCollection(parameter), rowBounds, handler);} catch (Exception e) {throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}
}@Override
public int update(String statement, Object parameter) {try {dirty = true;MappedStatement ms = configuration.getMappedStatement(statement);return executor.update(ms, wrapCollection(parameter));} catch (Exception e) {throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}
}@Override
public void commit(boolean force) {try {// 提交事务。提交之后将dirty设为false// 此时的缓存中视为没有脏数据executor.commit(isCommitOrRollbackRequired(force));dirty = false;} catch (Exception e) {throw ExceptionFactory.wrapException("Error committing transaction.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}
}@Override
public void rollback(boolean force) {try {executor.rollback(isCommitOrRollbackRequired(force));dirty = false;} catch (Exception e) {throw ExceptionFactory.wrapException("Error rolling back transaction.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}
}@Override
public List<BatchResult> flushStatements() {try {return executor.flushStatements();} catch (Exception e) {throw ExceptionFactory.wrapException("Error flushing statements.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}
}

代码比较简单,就不做过多的介绍。
DefaultSqlSessionFactory

DefaultSqlSessionFactory是一个工厂类,提供了两种创建DefaultSqlSession的方式,一种是通过数据源创建SqlSession,一种是通过用户传入的数据库连接对象来创建SqlSession。另外代码里有大量的openSession都是用于创建SqlSession对象的,但是其实现都是基于这两种方式,因此这里只把两种创建SqlSession的方式的代码贴出来,如下。

/*** 通过数据源去创建SqlSession* @param execType* @param level* @param autoCommit* @return*/
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;try {// 获取environment。这个是mybatis中配置的环境final Environment environment = configuration.getEnvironment();// 根据环境去获取TransactionFactory对象final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);// 创建Transaction对象tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);// 创建Executor对象final Executor executor = configuration.newExecutor(tx, execType);// 创建DefaultSqlSessionreturn new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) {closeTransaction(tx);// may have fetched a connection so lets call close()throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}
}/*** 通过用户提供的Connection对象去创建* @param execType* @param connection* @return*/
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {try {boolean autoCommit;try {autoCommit = connection.getAutoCommit();} catch (SQLException e) {// Failover to true, as most poor drivers// or databases won't support transactionsautoCommit = true;}final Environment environment = configuration.getEnvironment();final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);final Transaction tx = transactionFactory.newTransaction(connection);final Executor executor = configuration.newExecutor(tx, execType);return new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) {throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}
}

SqlSessionManager

SqlSessionManager同时实现了SqlSession接口和SQLSessionFactory接口,因此它拥有操作数据库的能力以及创建SqlSession的功能。

SQLSessionManager核心字段如下

private final SqlSessionFactory sqlSessionFactory;/*** localSqlSession中记录的SqlSession对象的代理对象*/
private final SqlSession sqlSessionProxy;/*** 记录当前线程的SqlSession对象*/
private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();

其中ThreadLocal的作用往往是作为当前线程的上下文,可以为当前线程提供全局变量。对ThreadLocal不了解的朋友也请查看我以前的文章。

SqlSessionManager提供了两种模式。一种是同一线程每次通过SqlSessionManager对象访问数据库时,都会创建一个DefaultSqlSession对象完成数据库操作,另一种则是使用localSqlSession绑定当前线程的SqlSession,在当前线程中循环使用同一个SqlSession。后者使用往往居多,这也是大家经常说的“SqlSession与线程绑定 ,每个请求都会创建SqlSession”的原因。

sqlSessionProxy是一个代理对象,在SqlSessionmanager的构造方法中使用JDK的动态代理创建完成,代码如下。

private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {this.sqlSessionFactory = sqlSessionFactory;// 使用动态代理去创建 SqlSessionthis.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(),new Class[]{SqlSession.class},new SqlSessionInterceptor());
}

SqlSessionManager中实现的SqlSession 接口方法,都是直接调用sqlSessionProxy字段记录的SqlSession代理对象的方法实现的。在创建该代理对象时使用到的SqlSessionInterceptor是SqlSessionManager的内部类,代码如下。

private class SqlSessionInterceptor implements InvocationHandler {public SqlSessionInterceptor() {// Prevent Synthetic Access}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 获取当前线程的SqlSessionfinal SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();if (sqlSession != null) {try {// SqlSession不为空就调用真正的SqlSession去完成数据库的操作return method.invoke(sqlSession, args);} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}} else {try (SqlSession autoSqlSession = openSession()) {// 如果当前线程的SqlSession为空,就创建新的SqlSession对象try {// 使用创建的SqlSession对象完成数据库操作final Object result = method.invoke(autoSqlSession, args);// 提交事务autoSqlSession.commit();return result;} catch (Throwable t) {autoSqlSession.rollback();throw ExceptionUtil.unwrapThrowable(t);}}}}
}

总结

SqlSession是单体mybatis使用最多的一个接口,可能我们在整合SSM之后就看不到这个接口了,但是其底层实现的时候也是会创建SqlSession的,虽然这个比较简单,但是也是相当重要的一个模块。
*************************************优雅的分割线 **********************************

分享一波:程序员赚外快-必看的巅峰干货

如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程

请关注微信公众号:HB荷包
在这里插入图片描述
一个能让你学习技术和赚钱方法的公众号,持续更新
*************************************优雅的分割线 **********************************
SimpleExecutor

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

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

相关文章

插入公式_一个小工具,彻底帮你搞定在Markdown中插入公式的问题

在编辑Markdown文档时&#xff0c;插入公式是一个挺麻烦的活儿。需要掌握LaTex语法。我自己看完语法后&#xff0c;直接放弃&#xff0c;这绝对是反人类的语法。&#xff08;好吧&#xff0c;是我不会用...&#xff09;但是&#xff0c;我相信你看了这篇文章后&#xff0c;绝对…

Mybatis源码阅读(一):Mybatis初始化1.2 —— 解析别名、插件、对象工厂、反射工具箱、环境

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

Google 修改 Chrome API,防止隐身模式检测

开发四年只会写业务代码&#xff0c;分布式高并发都不会还做程序员&#xff1f; 在使用 Chrome 浏览网页时&#xff0c;某些网站会使用某种方法来确定访问者是否处于隐身模式&#xff0c;这是一种隐私泄漏行为。Google 目前正在考虑修改 Chrome 的相关 API&#xff0c;来杜绝…

Mybatis源码阅读(一):Mybatis初始化1.1 解析properties、settings

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

JavaScript异步基础

唯一比不知道代码为什么崩溃更可怕的事情是&#xff0c;不知道为什么一开始它是工作的&#xff01;在 ECMA 规范的最近几次版本里不断有新成员加入&#xff0c;尤其在处理异步的问题上&#xff0c;更是不断推陈出新。然而&#xff0c;我们在享受便利的同时&#xff0c;也应该了…

Flutter、ReactNative、uniapp对比

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

多线程中ThreadLocal的使用

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

注解版poi操作工具

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

Kali Linux 2019.1 发布,Metasploit 更新到 5.0 版本

百度智能云 云生态狂欢季 热门云产品1折起>>> Kali Linux 2019.1 发布了&#xff0c;Kali 前身 BackTrack&#xff0c;它是一个基于 Debian 的 Linux 发行版&#xff0c;主要用于信息安全行业&#xff0c;其包含了一系列安全、渗透测试和取证工具。此版本 Linux 内核…

peewee mysql_scrapy中利用peewee插入Mysql

前两天老大布置一个任务&#xff0c;说爬下来的数据要存入数据库中&#xff0c;丢给我一个peewee&#xff0c;说用这个。当时的我两眼一抹黑&#xff0c;这是个什么东西呀&#xff0c;我知道scrapy的数据存入数据库是在pipelines中进行设置但是peewee是什么东西呢。经过两天不懈…

Java版数据结构与算法——线性表

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

基于 CODING 的 Spring Boot 持续集成项目

本文作者&#xff1a;CODING 用户 - 廖石荣 持续集成的概念 持续集成(Continuous integration,简称 CI&#xff09;是一种软件开发实践&#xff0c;即团队开发成员经常集成他们的工作&#xff0c;通常每个成员每天至少集成一次&#xff0c;也就意味着每天可能会发生多次集成。每…

Mybatis组成部分

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

一年java工作经验-面试总结

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

linux mysql python包_03_mysql-python模块, linux环境下python2,python3的

---恢复内容开始---1、Python2 正常[rootIP ~]#pip install mysql-pythonDEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 wont be maintained after that date. A future version of pip will drop …

两年Java工作经验应该会些什么技术

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

centos 6 mysql 5.7.13 编译安装_Centos 6.5 下面 源码编译 安装 Mysql 5.7.13

安装软件依赖包yum -y install gcc gcc-c ncurses ncurses-devel cmake下载软件包cd /usr/local/srcwget https://downloads.mysql.com/archives/get/file/mysql-5.7.13.tar.gz --no-check-certificate下载 boost 库&#xff0c;MySQL 5.7.5 开始Boost库是必需的cd /usr/loca…

LeetCode 237. 删除链表中的节点(Python3)

题目&#xff1a; 请编写一个函数&#xff0c;使其可以删除某个链表中给定的&#xff08;非末尾&#xff09;节点&#xff0c;你将只被给定要求被删除的节点。 现有一个链表 -- head [4,5,1,9]&#xff0c;它可以表示为: 示例 1: 输入: head [4,5,1,9], node 5 输出: [4,1,9…

一年Java经验应该会些什么

*************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如果以上内容对你觉得有用,并想获取更多的赚钱方式和免费的技术教程 请关注微信公众号:HB荷包 一个能让你学习技术和赚钱方法的公众号,持续更…

mysql查询各类课程的总学分_基于jsp+mysql的JSP学生选课信息管理系统

运行环境: 最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。IDE环境&#xff1a; Eclipse,Myeclipse,IDEA都可以硬件环境&#xff1a; windows 7/8/10 2G内存以上(推荐4G&#xff0c;4G以上更好)可以实现&#xff1a; 学生&#xff0c;教师角色的…