jdbc源码研究
JDBC介绍
JDBC(Java Data Base Connectivity
,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java
语言编写的类和接口组成。
开发者不必为每家数据通信协议的不同而疲于奔命,只需要面向JDBC提供的接口编程,在运行时,由对应的驱动程序操作对应的DB。
java.sql
包中包含用于以下方面的 API:
-
通过
DriverManager
实用程序建立与数据库的连接DriverManager
类:建立与驱动程序的连接SQLPermission
类:当代码在 Security Manager(比如 applet)中运行时提供权限,试图通过DriverManager
设置一个记录流Driver
接口:提供用来注册和连接基于 JDBC 技术(“JDBC 驱动程序”)的驱动程序的 API,通常仅由DriverManager
类使用DriverPropertyInfo
类:提供 JDBC 驱动程序的属性,不是供一般用户使用的
-
向数据库发送 SQL 语句
Statement
:用于发送基本 SQL 语句PreparedStatement
:用于发送准备好的语句或基本 SQL 语句(派生自Statement
)CallableStatement
:用于调用数据库存储过程(派生自PreparedStatement
)Connection
接口:提供创建语句以及管理连接及其属性的方法Savepoint
:在事务中提供保存点
-
获取和更新查询的结果
ResultSet
接口
-
SQL 类型到 Java 编程语言中的类和接口的标准映射关系
Array
接口:SQLARRAY
的映射关系Blob
接口:SQLBLOB
的映射关系Clob
接口:SQLCLOB
的映射关系Date
类:SQLDATE
的映射关系NClob
接口:SQLNCLOB
的映射关系Ref
接口:SQLREF
的映射关系RowId
接口:SQLROWID
的映射关系Struct
接口:SQLSTRUCT
的映射关系SQLXML
接口:SQLXML
的映射关系Time
类:SQLTIME
的映射关系Timestamp
类:SQLTIMESTAMP
的映射关系Types
类:提供用于 SQL 类型的常量
-
自定义映射 SQL 用户定义类型 (UDT) 到 Java 编程语言中的类
SQLData
接口:指定 UDT 到此类的一个实例的映射关系SQLInput
接口:提供用来从流中读取 UDT 属性的方法SQLOutput
接口:提供用来将 UDT 属性写回流中的方法
-
元数据
DatabaseMetaData
接口:提供有关数据库的信息ResultSetMetaData
接口:提供有关ResultSet
对象的列的信息ParameterMetaData
接口:提供有关PreparedStatement
命令的参数的信息
-
异常
SQLException
:由大多数方法在访问数据出问题时抛出,以及因为其他原因由其他一些方法抛出SQLWarning
:为了指示一个警告而抛出DataTruncation
:为了指示数据可能已经被截断而抛出BatchUpdateException
:为了指示并不是批量更新中的所有命令都成功执行而抛出
JDBC 的操作步骤
在进行JDBC
操作的时候可以按照以下的步骤完成:
- 加载数据库驱动程序,加载的时候需要将驱动程序配置到
classpath
之中 - 连接数据库,通过
Connection
接口和DriverManager
类完成 - 操作数据库,通过
Statement
、PreparedStatement
、ResultSet
三个接口完成 - 关闭数据库,在实际开发中数据库资源非常有限,操作完之后必须关闭
在JDBC 的操作中,如果要想进行数据库的连接,则必须按照以上的几步完成
- 通过
Class.forName()
加载数据库的驱动程序 - 通过
DriverManager
类进行数据库的连接,连接的时候要输入数据库的连接地址、用户名、密码 - 通过
Connection
接口接收连接 - 通过
Statement
接口操作数据。
代码示例
1、引入驱动
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.15</version></dependency>
2、加载驱动
3、建立与数据库的连接
4、创建Statement
Connection
接口的createStatement()
方法用于创建语句对象(Statement )。 Statement 对象负责对数据库执行查询。
5、执行SQL语句
6、关闭连接
public static void main(String[] args) {//连接对象Connection conn = null;//SQL statement 对象Statement stmt = null;try {//加载驱动Class.forName("com.mysql.cj.jdbc.Driver");//创建连接对象conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT","root", "root");//创建Statementstmt = conn.createStatement();System.out.println("连接成功,获取连接对象: " + conn);//执行SQL语句String sql = "update a set x = x +6 where id > 6";int count = stmt.executeUpdate(sql);System.out.println("返回结果count:" + count);} catch (ClassNotFoundException | SQLException e) {e.printStackTrace();} finally {//05、关闭连接对象if (stmt != null) {try {stmt.close();} catch (SQLException e) {e.printStackTrace();}}if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}
1、驱动类
com.mysql.jdbc.Driver
已被弃用。 新的驱动程序类是com.mysql.cj.jdbc.Driver
。 驱动程序通过SPI
自动注册,通常不需要手动加载驱动程序类。2、从
JDBC 4.0
开始,显式注册驱动程序是可选的。 我们只需要将相应的驱动jar
放在类路径中,然后JDBC驱动程序管理器就可以自动检测并加载驱动程序。3、因为新版本的数据库驱动需要指定UTC时区,将url地址后加上时区即可解决,
jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
4、从Java 7开始,JDBC能够使用
try-with-resources
语句来自动关闭Connection
,ResultSet
和Statement
类型的资源。
Java接口定义
Jdbc的主要接口定义在包java.sql
,javax.sql
下.
主要接口
- DriverManager: 管理驱动程序,主要用于调用驱动从数据库获取连接。
- Connection: 代表了一个数据库连接。
- Statement: 持有Sql语句,执行并返回执行后的结果。
- ResulSet: Sql执行完毕,返回的记过持有
接口定义
DriverManager
DriverManager
是用于管理JDBC驱动程序的基础服务。DriverManger 可以注册、删除、加载的驱动程序,可以根据给定的url
获取符合url
协议的驱动Driver
并建立Conenction
连接,进行数据库交互。当DriverManager
被使用时,DriverManager
类将尝试加载“ jdbc.drivers
”系统属性中的驱动程序类。
JDBC 4.0
驱动程序必须包含文件 META-INF/services/java.sql.Driver
,该文件包含了实现java.sql.Driver
的JDBC驱动程序的名称。例如,要加载my.sql.Driver
类,META-INF/services/java.sql.Driver
文件中将包含以下内容:my.sql.Driver
。
使用DriverManager
之后,应用程序不再需要使用 Class.forName()
显式加载JDBC
驱动程序了。已经使用 Class.forName()
显式加载JDBC
驱动的程序也不会受到影响,也无需刻意去修改。
当调用方法getConnection
时,DriverManager
将尝试从初始化时加载的驱动程序和当前应用程序显式加载的驱动程序中找到合适的驱动程序。
public interface Driver {/**尝试建立给定URL的数据库连接。 如果驱动程序意识到连接到给定URL的驱动程序类型错误,则应返回“ null”。 这是很常见的,因为当要求JDBC驱动程序管理器连接到给定的URL时,它将URL依次传递给每个已加载的驱动程序。注意:如果将属性指定为url的一部分,并且也在Properties对象中指定了属性,则该实现将由实现定义,以哪个值优先。 为了获得最大的可移植性,应用程序应仅指定一次属性。*/Connection connect(String url, java.util.Properties info)throws SQLException;/**
检索驱动程序是可以打开 给定URL的连接。 通常,如果驱动程序识别出 URL中指定的子协议,则将返回true;否则,将返回false。*/boolean acceptsURL(String url) throws SQLException;/**获取有关此驱动程序可能的属性的信息。getPropertyInfo方法旨在允许通用的GUI工具发现应该提示的属性,以便获得足够的信息以连接到数据库。 */DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info)throws SQLException;/**获取驱动程序的主版本号。 最初应为1。*/int getMajorVersion();int getMinorVersion();/**报告此驱动程序是否是正版JDBC Compliant™驱动程序。 如果驱动程序通过了JDBC兼容性测试,则仅在此处报告true。 否则需要返回false。JDBC合规性要求对JDBC API的完全支持和对SQL 92 Entry Level的完全支持。 期望所有主要的商业数据库都可以使用符合JDBC的驱动程序。*/boolean jdbcCompliant();//------------------------- JDBC 4.1 -----------------------------------/**返回此驱动程序使用的所有Logger的父Logger。 这应该是距离根Logger最远的Logger,它仍然是该驱动程序使用的所有Logger的祖先。 配置此Logger将影响驱动程序生成的所有日志消息。 在最坏的情况下,它可能是根Logger。*/public Logger getParentLogger() throws SQLFeatureNotSupportedException;
}
Class.forName()
手动加载驱动
Class.forName()
将对应的驱动类加载到内存中时,会执行驱动类中的static 静态代码快,创建一个驱动Driver的实例,注册到DriverManager
中,供DriverManager
使用。
//加载MySQL 数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
DriverManager 源码分析
DriverManager 加载驱动
DriverManager
作为 Driver 的管理器,在首次被使用时,会执行其定义的static静态代码块,在静态代码快中,有一个 loadInitialDrivers()
静态方法,会首先加载配置在jdbc.drivers
系统属性内的驱动Driver。
static {loadInitialDrivers();println("JDBC DriverManager initialized");}private static void loadInitialDrivers() {String drivers;//尝试从系统属性"jdbc.drivers"中获取驱动类try {drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {public String run() {return System.getProperty("jdbc.drivers");}});} catch (Exception ex) {drivers = null;}//使用ServiceLoader 加载驱动程序AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);Iterator<Driver> driversIterator = loadedDrivers.iterator();// 加载这些驱动程序,以便可以实例化它们。try{while(driversIterator.hasNext()) {driversIterator.next();}} catch(Throwable t) {// Do nothing}return null;}});println("DriverManager.initialize: jdbc.drivers = " + drivers);//jdbc.drivers 中的驱动处理if (drivers == null || drivers.equals("")) {return;}String[] driversList = drivers.split(":");println("number of Drivers:" + driversList.length);for (String aDriver : driversList) {try {println("DriverManager.Initialize: loading " + aDriver);Class.forName(aDriver, true,ClassLoader.getSystemClassLoader());} catch (Exception ex) {println("DriverManager.Initialize: load failed: " + ex);}}}
DriverManager 注册驱动
//同步注册
public static synchronized void registerDriver(java.sql.Driver driver)throws SQLException {registerDriver(driver, null);}//CopyOnWriteArrayListprivate final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();public static synchronized void registerDriver(java.sql.Driver driver,DriverAction da)throws SQLException {/* Register the driver if it has not already been added to our list */if(driver != null) {registeredDrivers.addIfAbsent(new DriverInfo(driver, da));} else {// This is for compatibility with the original DriverManagerthrow new NullPointerException();}println("registerDriver: " + driver);}
DriverManager 取消注册驱动
@CallerSensitivepublic static synchronized void deregisterDriver(Driver driver)throws SQLException {if (driver == null) {return;}SecurityManager sec = System.getSecurityManager();if (sec != null) {sec.checkPermission(DEREGISTER_DRIVER_PERMISSION);}println("DriverManager.deregisterDriver: " + driver);DriverInfo aDriver = new DriverInfo(driver, null);//包含if(registeredDrivers.contains(aDriver)) {if (isDriverAllowed(driver, Reflection.getCallerClass())) {DriverInfo di = registeredDrivers.get(registeredDrivers.indexOf(aDriver));// If a DriverAction was specified, Call it to notify the// driver that it has been deregisteredif(di.action() != null) {di.action().deregister();}//移除registeredDrivers.remove(aDriver);} else {// If the caller does not have permission to load the driver then// throw a SecurityException.throw new SecurityException();}} else {println(" couldn't find driver to unload");}}
DriverManager 创建连接
通过遍历已加载的驱动程序,分别尝试连接指定的数据库,如果连接上则返回连接对象。
@CallerSensitivepublic static Connection getConnection(String url)throws SQLException {java.util.Properties info = new java.util.Properties();return (getConnection(url, info, Reflection.getCallerClass()));}@CallerSensitivepublic static Connection getConnection(String url,java.util.Properties info) throws SQLException {return (getConnection(url, info, Reflection.getCallerClass()));}@CallerSensitivepublic static Connection getConnection(String url,String user, String password) throws SQLException {java.util.Properties info = new java.util.Properties();if (user != null) {info.put("user", user);}if (password != null) {info.put("password", password);}return (getConnection(url, info, Reflection.getCallerClass()));}private static Connection getConnection(String url, java.util.Properties info, Class<?> caller) throws SQLException {/*当callerCl为空时,检查应用程序的类加载器,以便可以从此处加载rt.jar外部的JDBC驱动程序类。*/ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;synchronized(DriverManager.class) {// synchronize loading of the correct classloader.if (callerCL == null) {callerCL = Thread.currentThread().getContextClassLoader();}}if(url == null) {throw new SQLException("The url cannot be null", "08001");}println("DriverManager.getConnection(\"" + url + "\")");SQLException reason = null;// 遍历每个驱动尝试连接指定的数据库地址for(DriverInfo aDriver : registeredDrivers) {// If the caller does not have permission to load the driver then// skip it.if(isDriverAllowed(aDriver.driver, callerCL)) {try {println(" trying " + aDriver.driver.getClass().getName());Connection con = aDriver.driver.connect(url, info);if (con != null) {// Success!println("getConnection returning " + aDriver.driver.getClass().getName());return (con);}} catch (SQLException ex) {if (reason == null) {reason = ex;}}} else {println(" skipping: " + aDriver.getClass().getName());}}// if we got here nobody could connect.if (reason != null) {println("getConnection failed: " + reason);throw reason;}println("getConnection: no suitable driver found for "+ url);throw new SQLException("No suitable driver found for "+ url, "08001");}
DataSource
接口提供了另一种连接数据源的方法。 使用DataSource
对象是连接数据源的首选方法。
Wrapper
java.sql.Wrapper
是 JDBC 的接口,当相关实例实际上是代理类时,该接口提供检索委托实例的功能。
许多 JDBC 驱动程序实现使用包装器模式提供超越传统 JDBC API
的扩展功能,传统 JDBC API
是特定于数据源的。开发人员可能希望访问那些被包装(代理)为代表实际资源代理类实例的资源。
public interface Wrapper {<T> T unwrap(java.lang.Class<T> iface) throws java.sql.SQLException;boolean isWrapperFor(java.lang.Class<?> iface) throws java.sql.SQLException;
}
T unwrap(java.lang.Class iface)
返回一个实现给定接口的对象,以允许访问非标准方法或代理未公开的标准方法。
如果接收者实现了该接口,那么结果是接收者或接收者代理。如果接收者是包装器且包装对象实现了该接口,那么结果是包装对象或包装对象的代理。否则,返回对该包装对象或该结果的代理进行递归调用的结果。如果接收者不是包装器且未实现该接口,则抛出 sqlexception。
boolean isWrapperFor(java.lang.Class<?> iface)
如果此方法实现了接口参数,或者直接或间接地对该对象进行了包装,则返回true。 否则返回false。
如果实现了接口,那么返回true,否则如果这是一个包装器,那么返回在包装对象上递归调用isWrapperFor
的结果。
如果不实现接口并且不是包装器,则返回false。
与 unwrap
相比,此方法应作为一种低成本操作来实现,以便调用者可以使用此方法来避免可能失败的昂贵的 unwrap 调用。 如果此方法返回true,则使用相同参数调用unwrap
应该会成功。
java.sql.Wrapper
主要有以下子接口:
- DataSource:该工厂用于提供到此 DataSource 对象所表示的物理数据源的连接。
- Connection:与特定数据库的连接(会话)。
- DatabaseMetaData:关于数据库的整体综合信息。
- ParameterMetaData:可用于获取关于 PreparedStatement 对象中每个参数标记的类型和属性信息的对象。
- ResultSet:表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。
- ResultSetMetaData:可用于获取关于 ResultSet 对象中列的类型和属性信息的对象。
- Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。
- CallableStatement:用于执行 SQL 存储过程的接口。
- PreparedStatement:表示预编译的 SQL 语句的对象。
- RowSet:该接口添加了对 JavaBeansTM 组件模型的 JDBC API 支持。
- RowSetMetaData:该对象包含关于 RowSet 对象的列的信息。
Connection
Connection 是Java应用程序和特定数据库之间的会话。 用来执行SQL语句,并在连接的上下文中返回结果。
public interface Connection extends Wrapper, AutoCloseable {/**创建一个Statement对象,用于将SQL语句发送到数据库。 不带参数的SQL语句通常使用Statement对象执行。 如果多次执行同一条SQL语句,则使用PreparedStatement对象可能会更合适。
默认情况下,使用返回的Statement对象创建的结果集的类型为TYPE_FORWARD_ONLY,并发级别为CONCUR_READ_ONLY。 可以通过调用getHoldability()确定创建的结果集的可保存性。*/Statement createStatement() throws SQLException;/***/PreparedStatement prepareStatement(String sql)throws SQLException;CallableStatement prepareCall(String sql) throws SQLException;String nativeSQL(String sql) throws SQLException;void setAutoCommit(boolean autoCommit) throws SQLException;boolean getAutoCommit() throws SQLException;void commit() throws SQLException;void rollback() throws SQLException;void close() throws SQLException;boolean isClosed() throws SQLException;DatabaseMetaData getMetaData() throws SQLException;void setReadOnly(boolean readOnly) throws SQLException;boolean isReadOnly() throws SQLException;void setCatalog(String catalog) throws SQLException;String getCatalog() throws SQLException;/*** A constant indicating that transactions are not supported.*/int TRANSACTION_NONE = 0;int TRANSACTION_READ_UNCOMMITTED = 1;int TRANSACTION_READ_COMMITTED = 2;int TRANSACTION_REPEATABLE_READ = 4;int TRANSACTION_SERIALIZABLE = 8;void setTransactionIsolation(int level) throws SQLException;int getTransactionIsolation() throws SQLException;SQLWarning getWarnings() throws SQLException;void clearWarnings() throws SQLException;//--------------------------JDBC 2.0-----------------------------Statement createStatement(int resultSetType, int resultSetConcurrency)throws SQLException;PreparedStatement prepareStatement(String sql, int resultSetType,int resultSetConcurrency)throws SQLException;CallableStatement prepareCall(String sql, int resultSetType,int resultSetConcurrency) throws SQLException;java.util.Map<String,Class<?>> getTypeMap() throws SQLException;void setTypeMap(java.util.Map<String,Class<?>> map) throws SQLException;//--------------------------JDBC 3.0-----------------------------void setHoldability(int holdability) throws SQLException;int getHoldability() throws SQLException;Savepoint setSavepoint() throws SQLException;Savepoint setSavepoint(String name) throws SQLException;void rollback(Savepoint savepoint) throws SQLException;void releaseSavepoint(Savepoint savepoint) throws SQLException;Statement createStatement(int resultSetType, int resultSetConcurrency,int resultSetHoldability) throws SQLException;PreparedStatement prepareStatement(String sql, int resultSetType,int resultSetConcurrency, int resultSetHoldability)throws SQLException;CallableStatement prepareCall(String sql, int resultSetType,int resultSetConcurrency,int resultSetHoldability) throws SQLException;PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)throws SQLException;PreparedStatement prepareStatement(String sql, int columnIndexes[])throws SQLException;PreparedStatement prepareStatement(String sql, String columnNames[])throws SQLException;Clob createClob() throws SQLException;Blob createBlob() throws SQLException;NClob createNClob() throws SQLException;SQLXML createSQLXML() throws SQLException;boolean isValid(int timeout) throws SQLException;void setClientInfo(String name, String value)throws SQLClientInfoException;void setClientInfo(Properties properties)throws SQLClientInfoException;String getClientInfo(String name)throws SQLException;Properties getClientInfo()throws SQLException;Array createArrayOf(String typeName, Object[] elements) throws
SQLException;Struct createStruct(String typeName, Object[] attributes)
throws SQLException;//--------------------------JDBC 4.1 -----------------------------void setSchema(String schema) throws SQLException;String getSchema() throws SQLException;void abort(Executor executor) throws SQLException;void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException;int getNetworkTimeout() throws SQLException;
}
Statement及子接口
PreparedStatement 表示预编译的SQL语句的对象,SQL语句已预编译并存储在PreparedStatement对象中。 然后可以使用该对象多次有效地执行该语句。
String sql = "insert into users values(?,?,?)";
//可以通过setter来为每个参数赋值。pstmt.setBigDecimal(1, 153833.00)pstmt.setInt(2, 110592)
public interface Statement extends Wrapper, AutoCloseable {ResultSet executeQuery(String sql) throws SQLException;int executeUpdate(String sql) throws SQLException;void close() throws SQLException;//----------------------------------------------------------------------int getMaxFieldSize() throws SQLException;void setMaxFieldSize(int max) throws SQLException;int getMaxRows() throws SQLException;void setMaxRows(int max) throws SQLException;void setEscapeProcessing(boolean enable) throws SQLException;int getQueryTimeout() throws SQLException;void setQueryTimeout(int seconds) throws SQLException;void cancel() throws SQLException;SQLWarning getWarnings() throws SQLException;void clearWarnings() throws SQLException;void setCursorName(String name) throws SQLException;boolean execute(String sql) throws SQLException;ResultSet getResultSet() throws SQLException;int getUpdateCount() throws SQLException;boolean getMoreResults() throws SQLException;//--------------------------JDBC 2.0-----------------------------void setFetchDirection(int direction) throws SQLException;int getFetchDirection() throws SQLException;void setFetchSize(int rows) throws SQLException;int getFetchSize() throws SQLException;int getResultSetConcurrency() throws SQLException;int getResultSetType() throws SQLException;/** 批次 加 sql */void addBatch( String sql ) throws SQLException;void clearBatch() throws SQLException;int[] executeBatch() throws SQLException;Connection getConnection() throws SQLException;//--------------------------JDBC 3.0-----------------------------int CLOSE_CURRENT_RESULT = 1;int KEEP_CURRENT_RESULT = 2;int CLOSE_ALL_RESULTS = 3;int SUCCESS_NO_INFO = -2;int EXECUTE_FAILED = -3;int RETURN_GENERATED_KEYS = 1;int NO_GENERATED_KEYS = 2;boolean getMoreResults(int current) throws SQLException;ResultSet getGeneratedKeys() throws SQLException;int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException;int executeUpdate(String sql, int columnIndexes[]) throws SQLException;int executeUpdate(String sql, String columnNames[]) throws SQLException;boolean execute(String sql, int autoGeneratedKeys) throws SQLException;boolean execute(String sql, int columnIndexes[]) throws SQLException;boolean execute(String sql, String columnNames[]) throws SQLException;int getResultSetHoldability() throws SQLException;boolean isClosed() throws SQLException;void setPoolable(boolean poolable)throws SQLException;boolean isPoolable()throws SQLException;//--------------------------JDBC 4.1 -----------------------------public void closeOnCompletion() throws SQLException;public boolean isCloseOnCompletion() throws SQLException;//--------------------------JDBC 4.2 -----------------------------default long getLargeUpdateCount() throws SQLException {throw new UnsupportedOperationException("getLargeUpdateCount not implemented");}default void setLargeMaxRows(long max) throws SQLException {throw new UnsupportedOperationException("setLargeMaxRows not implemented");}default long getLargeMaxRows() throws SQLException {return 0;}default long[] executeLargeBatch() throws SQLException {throw new UnsupportedOperationException("executeLargeBatch not implemented");}default long executeLargeUpdate(String sql) throws SQLException {throw new UnsupportedOperationException("executeLargeUpdate not implemented");}default long executeLargeUpdate(String sql, int autoGeneratedKeys)throws SQLException {throw new SQLFeatureNotSupportedException("executeLargeUpdate not implemented");}default long executeLargeUpdate(String sql, int columnIndexes[]) throws SQLException {throw new SQLFeatureNotSupportedException("executeLargeUpdate not implemented");}default long executeLargeUpdate(String sql, String columnNames[])throws SQLException {throw new SQLFeatureNotSupportedException("executeLargeUpdate not implemented");}
}
public interface PreparedStatement extends Statement {ResultSet executeQuery() throws SQLException;int executeUpdate() throws SQLException;/** 下面是各种数据类型的设置 */void setNull(int parameterIndex, int sqlType) throws SQLException;void setXXXX(int parameterIndex, <Type> x) throws SQLException;void setAsciiStream(int parameterIndex, java.io.InputStream x, int length)throws SQLException;@Deprecatedvoid setUnicodeStream(int parameterIndex, java.io.InputStream x,int length) throws SQLException;void setBinaryStream(int parameterIndex, java.io.InputStream x,int length) throws SQLException;void clearParameters() throws SQLException;//----------------------------------------------------------------------// Advanced features:void setObject(int parameterIndex, Object x, int targetSqlType)throws SQLException;void setObject(int parameterIndex, Object x) throws SQLException;boolean execute() throws SQLException;//--------------------------JDBC 2.0-----------------------------/** 把当前参数 的设置 加到批次 */void addBatch() throws SQLException;void setYYY(int parameterIndex, YYY y) throws SQLException;//------------------------- JDBC 3.0 -----------------------------------void setURL(int parameterIndex, java.net.URL x) throws SQLException;ParameterMetaData getParameterMetaData() throws SQLException;//------------------------- JDBC 4.0 -----------------------------------/** 新增的数据类型*/void setRowId(int parameterIndex, RowId x) throws SQLException;void setNString(int parameterIndex, String value) throws SQLException;void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException;//------------------------- JDBC 4.2 -----------------------------------default void setObject(int parameterIndex, Object x, SQLType targetSqlType,int scaleOrLength) throws SQLException {throw new SQLFeatureNotSupportedException("setObject not implemented");}default void setObject(int parameterIndex, Object x, SQLType targetSqlType)throws SQLException {throw new SQLFeatureNotSupportedException("setObject not implemented");}default long executeLargeUpdate() throws SQLException {throw new UnsupportedOperationException("executeLargeUpdate not implemented");}
}
使用 Statement 对象进行批处理更新
Statement
,PreparedStatement
和 CallableStatement
对象具有与其关联的命令列表。 该列表在创建时与 Statement 对象相关联,初始是空的。 您可以使用addBatch
方法将SQL命令添加到此列表,并使用clearBatch
方法将其清空。 完成将语句添加到列表后,请调用executeBatch
方法将其全部发送到数据库以作为一个单元或批处理执行。
public static void main(String[] args) throws SQLException {batchUpdate();}/*** 使用 Statement 对象进行批处理更新*/private static void batchUpdate() {//Step 1: 创建 Connection 对象try (Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT", "root", "root");// Step 2:使用 connection 创建 statement 对象Statement statement = connection.createStatement()) {connection.setAutoCommit(false);statement.addBatch("INSERT INTO Users VALUES (1, 'XXX', 'xxx@qq.com', 'China', '1234');");statement.addBatch("INSERT INTO Users VALUES (2, 'YYY', 'yyy@qq.com', 'China', '1235');");//批处理int[] updateCounts = statement.executeBatch();System.out.println(Arrays.toString(updateCounts));connection.commit();} catch (BatchUpdateException batchUpdateException) {printBatchUpdateException(batchUpdateException);} catch (SQLException e) {printSQLException(e);}}
进行参数化的批量更新
private static void parameterizedBatchUpdate() {String INSERT_USERS_SQL = "INSERT INTO users" + " (id, name, email, country, password) VALUES " +" (?, ?, ?, ?, ?);";try (Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT", "root", "root");PreparedStatement preparedStatement = connection.prepareStatement(INSERT_USERS_SQL)) {connection.setAutoCommit(false);preparedStatement.setInt(1, 8);preparedStatement.setString(2, "XXX");preparedStatement.setString(3, "xxx@qq.com");preparedStatement.setString(4, "China");preparedStatement.setString(5, "1");preparedStatement.addBatch();preparedStatement.setInt(1, 9);preparedStatement.setString(2, "YYYY");preparedStatement.setString(3, "yyyy@qq.com");preparedStatement.setString(4, "China");preparedStatement.setString(5, "2");preparedStatement.addBatch();preparedStatement.setInt(1, 10);preparedStatement.setString(2, "ZZZZ");preparedStatement.setString(3, "zzzz@qq.com");preparedStatement.setString(4, "China");preparedStatement.setString(5, "3");preparedStatement.addBatch();preparedStatement.setInt(1, 11);preparedStatement.setString(2, "DDDD");preparedStatement.setString(3, "dddd.com");preparedStatement.setString(4, "China");preparedStatement.setString(5, "4");preparedStatement.addBatch();int[] updateCounts = preparedStatement.executeBatch();System.out.println(Arrays.toString(updateCounts));connection.commit();connection.setAutoCommit(true);} catch (BatchUpdateException batchUpdateException) {printBatchUpdateException(batchUpdateException);} catch (SQLException e) {printSQLException(e);}}
ResultSet
ResultSet
接口提供了用于检索和处理已获得结果集的方法,并且ResultSet
对象具有不同的功能和特性。 这些特性是type
(类型), concurrency
(并发性), cursor holdability
(游标可保持性)。
ResultSet
对象维护一个游标,该游标指向其当前数据行。 next
方法将光标移动到下一行,当ResultSet
对象中没有更多行时它返回false
,因此可以在while循环中使用它来迭代结果集。
默认的 ResultSet
对象是不可更新的,并且只有仅向前移动的光标。 因此,您只能从第一行到最后一行迭代一次。
可以生成可滚动或可更新的ResultSet对象。 下面的代码片段(其中con是有效的Connection对象)说明了如何创建一个可滚动且对其他更新不敏感并且可更新的结果集。
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);ResultSet rs = stmt.executeQuery("SELECT a, b FROM test");
ResultSet
接口提供了用于从当前行检索列值的getter
方法(getBoolean,getLong等)。 可以使用列的索引号或列的名称来检索值。 通常,使用列索,列索引编号从1
开始编号。为了实现最大的可移植性,应按从左到右的顺序读取每一行中的结果集列,并且每一列只能读取一次。
对于getter
方法,JDBC驱动程序尝试将基础数据转换为getter
方法中指定的Java类型,并返回合适的Java值。 JDBC
规范具有一个表,该表显示了ResultSet
getter方法可以使用的从SQL类型到Java类型的映射。
用作getter
方法的列名不区分大小写。 当使用列名调用getter
方法并且多个列具有相同的名称时,将返回第一个匹配列的值。 对于在查询中未明确命名的列,最好使用列号。 如果使用了列名,则应注意确保它们的唯一,这可以通过SQL AS
子句来确保。
在JDBC 2.0 API
中,向该接口添加了一组更新程序方法。 有关getter
方法的参数的注释也适用于updater方法的参数。
更新方法有两种使用方式:
1、更新当前行中的列值:在可滚动的ResultSet
对象中,光标可以前后移动,移动到绝对位置或相对于当前行的位置
rs.absolute(6); // 移动光标到 rs 的第6行
rs.updateString("NAME", "xxx"); // 更新 NAME 列的值为 xxx
rs.updateRow(); // 更新当前数据源 rs 中的第6行操作
2、将列值插入到插入行中:可更新的ResultSet对象具有与其关联的特殊行,该行用作构建要插入的行的暂存区。
rs.moveToInsertRow(); // 移动游标到插入行rs.updateString(1, "xxx"); // 更新插入行第一列的值为 xxxrs.updateInt(2,3); // 更新第二列的值为 3rs.updateBoolean(3, true); // 更新第三列的值为 truers.insertRow();rs.moveToCurrentRow();
ResultSet 类型
ResultSet
对象的类型在两个方面确定其功能级别:游标的操作方式以及ResultSet
对象如何反映对基础数据源进行的并发更改。
游标的操作方式:
-
TYPE_FORWARD_ONLY
结果集无法滚动,它的光标只能从第一行之前移到最后一行之后。 结果集中包含的行取决于基础数据库如何生成的结果。 即,它包含在执行查询时或在检索行时满足查询条件的行。 -
TYPE_SCROLL_INSENSITIVE
结果集可以滚动, 它的光标可以相对于当前位置向前和向后移动,并且可以移动到绝对位置。 结果集在打开时对基础数据源所做的更改不敏感。 它包含在执行查询时或在检索行时满足查询条件的行。 -
TYPE_SCROLL_SENSITIVE
结果可以滚动,它的光标可以相对于当前位置向前和向后移动,并且可以移动到绝对位置。 结果集反映在结果集保持打开状态时对基础数据源所做的更改。
ResultSet 并发性:
ResultSet 对象的并发性确定了支持什么级别的更新功能。
- CONCUR_READ_ONLY:无法使用ResultSet接口更新ResultSet对象。
- CONCUR_UPDATABLE:可以使用ResultSet接口更新ResultSet对象。
Cursor Holdability(游标可保持性)
调用方法Connection.commit
可以关闭在当前事务期间创建的ResultSet
对象。 但是,在某些情况下,这可能不是所需的行为。 ResultSet
属性的可保留性使应用程序可以控制在调用提交时是否关闭ResultSet
对象(光标)。
可以将以下ResultSet
常量提供给Connection方法的createStatement
,prepareStatement
和prepareCall
:
HOLD_CURSORS_OVER_COMMIT
: ResultSet游标未关闭,它是可保持的,调用方法commit时,它们保持打开状态。 如果您的应用程序主要使用只读的ResultSet对象,则可保持游标可能是理想的选择。CLOSE_CURSORS_AT_COMMIT
: 调用commit方法时,将关闭ResultSet对象(光标)。 调用此方法时关闭游标可以提高某些应用程序的性能。
ResultSetMetaData
ResultSetMetaData
对象用于收集ResultSet
的所有信息,例如列的类型和属性,列数,列的名称,列的数据类型等。简单来说,它用于收集 ResultSet
的信息。
ResultSetMetaData
封装了描述 ResultSet
对象的数据,内部提供了大量的方法来获取 ResultSet
的信息
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM test");
ResultSetMetaData rsmd = rs.getMetaData();
//获取有多少列
int numberOfColumns = rsmd.getColumnCount();
boolean b = rsmd.isSearchable(1);
常用方法
方法 | 描述 |
---|---|
int getColumnCount() throws SQLException | 返回 ResultSet 对象列的数量 |
String getColumnName(int column) throws SQLException | 根据指定的索引获取列名 |
int getColumnType(int column) throws SQLException | 根据指定索引检索指定列的SQL类型 |
String getTableName(int column) throws SQLException | 根据列索引获取表名 |
String getSchemaName(int column) | 获取指定列的表的结构 |
int getScale(int column) throws SQLException | 获取指定列的小数点右边的位数。 对于不适用小数位数的数据类型,返回0。 |
int getPrecision(int column) throws SQLException | 获取指定列的指定列大小。 |
DatabaseMetaData
DatabaseMetaData
接口提供了获取数据库元数据的方法,例如数据库名称,数据库版本,驱动程序名称,表总数,视图总数等。
数据库实现
数据库的实现以mysql
为例。
Driver实现
当Class.forName("com.mysql.jdbc.Driver")
被执行时,com.mysql.jdbc.Driver
类就会被加载,同时也在静态代码块中完成了向DriverManager
的注册
public class Driver extends NonRegisteringDriver implements java.sql.Driver {public Driver() throws SQLException {}static {try {DriverManager.registerDriver(new Driver());} catch (SQLException var1) {throw new RuntimeException("Can't register driver!");}}
}
具体实现在类NonRegisteringDriver
中。
public class NonRegisteringDriver implements Driver {//System.getProperty("os.name");public static String getOSName() {return Constants.OS_NAME;}//System.getProperty("os.arch");public static String getPlatform() {return Constants.OS_ARCH;}static int getMajorVersionInternal() {return StringUtils.safeIntParse("8");}static int getMinorVersionInternal() {return StringUtils.safeIntParse("0");}public NonRegisteringDriver() throws SQLException {}public boolean acceptsURL(String url) throws SQLException {try {//helper类return ConnectionUrl.acceptsUrl(url);} catch (CJException var3) {throw SQLExceptionsMapping.translateException(var3);}}public Connection connect(String url, Properties info) throws SQLException {try {try {if (!ConnectionUrl.acceptsUrl(url)) {return null;} else {ConnectionUrl conStr = ConnectionUrl.getConnectionUrlInstance(url, info);switch (conStr.getType()) {//单实例case SINGLE_CONNECTION:return ConnectionImpl.getInstance(conStr.getMainHost());case LOADBALANCE_CONNECTION:return LoadBalancedConnectionProxy.createProxyInstance((LoadbalanceConnectionUrl)conStr);case FAILOVER_CONNECTION:return FailoverConnectionProxy.createProxyInstance(conStr);//复制case REPLICATION_CONNECTION:return ReplicationConnectionProxy.createProxyInstance((ReplicationConnectionUrl)conStr);default:return null;}}} catch (UnsupportedConnectionStringException var5) {return null;} catch (CJException var6) {throw (UnableToConnectException)ExceptionFactory.createException(UnableToConnectException.class, Messages.getString("NonRegisteringDriver.17", new Object[]{var6.toString()}), var6);}} catch (CJException var7) {throw SQLExceptionsMapping.translateException(var7);}}public int getMajorVersion() {return getMajorVersionInternal();}public int getMinorVersion() {return getMinorVersionInternal();}public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {try {String host = "";String port = "";String database = "";String user = "";String password = "";if (!StringUtils.isNullOrEmpty(url)) {//解析urlConnectionUrl connStr = ConnectionUrl.getConnectionUrlInstance(url, info);if (connStr.getType() == Type.SINGLE_CONNECTION) {HostInfo hostInfo = connStr.getMainHost();info = hostInfo.exposeAsProperties();}}if (info != null) {host = info.getProperty(PropertyKey.HOST.getKeyName());port = info.getProperty(PropertyKey.PORT.getKeyName());database = info.getProperty(PropertyKey.DBNAME.getKeyName());user = info.getProperty(PropertyKey.USER.getKeyName());password = info.getProperty(PropertyKey.PASSWORD.getKeyName());}DriverPropertyInfo hostProp = new DriverPropertyInfo(PropertyKey.HOST.getKeyName(), host);hostProp.required = true;hostProp.description = Messages.getString("NonRegisteringDriver.3");DriverPropertyInfo portProp = new DriverPropertyInfo(PropertyKey.PORT.getKeyName(), port);portProp.required = false;portProp.description = Messages.getString("NonRegisteringDriver.7");DriverPropertyInfo dbProp = new DriverPropertyInfo(PropertyKey.DBNAME.getKeyName(), database);dbProp.required = false;dbProp.description = Messages.getString("NonRegisteringDriver.10");DriverPropertyInfo userProp = new DriverPropertyInfo(PropertyKey.USER.getKeyName(), user);userProp.required = true;userProp.description = Messages.getString("NonRegisteringDriver.13");DriverPropertyInfo passwordProp = new DriverPropertyInfo(PropertyKey.PASSWORD.getKeyName(), password);passwordProp.required = true;passwordProp.description = Messages.getString("NonRegisteringDriver.16");//5个关键属性。DriverPropertyInfo[] dpi = (new JdbcPropertySetImpl()).exposeAsDriverPropertyInfo(info, 5);dpi[0] = hostProp;dpi[1] = portProp;dpi[2] = dbProp;dpi[3] = userProp;dpi[4] = passwordProp;return dpi;} catch (CJException var15) {throw SQLExceptionsMapping.translateException(var15);}}public boolean jdbcCompliant() {return false;}public Logger getParentLogger() throws SQLFeatureNotSupportedException {throw new SQLFeatureNotSupportedException();}static {try {Class.forName(AbandonedConnectionCleanupThread.class.getName());} catch (ClassNotFoundException var1) {}}
}
ConnectionUrl
附录
参考
java.sql包API
PreparedStatement 性能
数据库解析SQL字符串并为其创建查询计划需要花费时间。 查询计划则是对数据库如何以最有效的方式执行查询的分析。
如果为每个查询或对数据库的更新提交新的完整SQL语句,则数据库必须解析SQL,并为查询创建查询计划。 通过重用现有的 PreparedStatement,您可以将SQL解析和查询计划复用于后续查询。 通过减少每次执行的解析和查询计划开销,这可以加快查询的执行速度。
PreparedStatement 的复用有以下两个方面:
- JDBC驱动程序重用 PreparedStatement。
- 数据库重用 PreparedStatement。
首先,JDBC驱动程序可以在内部缓存PreparedStatement
对象,从而可以重用PreparedStatement
对象。 这样可以节省少许PreparedStatement
创建时间。
其次,缓存的解析和查询计划可能会使用相同的数据库跨Java应用程序(例如集群中的应用程序服务器)重用。
相关文章:
jdbc源码研究
JDBC介绍 JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。 开发者不必为每家数据通信协议的不同而疲于奔命&#…...
挠性及刚挠结合印制电路技术
1.1挠性印制电路板概述 20世纪70年代末期,以日本厂商为主导,逐渐将挠性印制电路板(flexible printedcircuit board,FPCB,简称为FPC)广泛应用于计算机、照相机、打印机、汽车音响、硬盘驱动器等电子信息产品中。20世纪90年代初期&…...
Python+OpenGL绘制3D模型(七)制作3dsmax导出插件
系列文章 一、逆向工程 Sketchup 逆向工程(一)破解.skp文件数据结构 Sketchup 逆向工程(二)分析三维模型数据结构 Sketchup 逆向工程(三)软件逆向工程从何处入手 Sketchup 逆向工程(四…...
MediaPipeUnityPlugin Win10环境搭建(22年3月的记录,新版本已完全不同,这里只做记录)
https://github.com/homuler/MediaPipeUnityPlugin You cannot build libraries for Android with the following steps. 1、安装msys2配置系统环境变量Path添加 C:\msys64\usr\bin 执行 pacman -Su 执行 pacman -S git patch unzip 2、安装Python3.9.10 勾选系统环境变量 …...
Nginx - location块中的alias和try_files重定向
nginx.conf片段: location /logo/general/ {autoindex_localtime on;alias /opt/config/;try_files /logo/logo.png /www/html/logo.png 404;} 意为:访问/logo/general/地址时, 如:访问http://127.0.0.1/logo/general/logo.png…...
二刷Laravel 教程(用户模型)总结Ⅲ
一、数据库迁移 当我们运行迁移时,up 方法会被调用;(创建表) 当我们回滚迁移时,down 方法会被调用。(删除表) public function up() { //create 方法会接收两个参数:一个是数据…...
安装PyTorch及环境配置(应用于Python上的YOLO)
这个基本都是Bilibili网站里面叫“小手丫子”up的视频教程,此前自己需要装了好几次又卸载了好几次,现在根据视频教学整理出来自己所理解的文档。 注意事项 1.安装的pycharm版本和anaconda版本无要求。 2.运行pycharm尽量以管理员身份运行。 3.Cuda是独…...
【194】PostgreSQL 14.5 编写SQL从身份证号中查找性别,并且更新性别字段。
假设有一张用户表 t_user ,该表设计如下: id: character varying 主键 name: character varying 姓名 idcard: character varying 身份证号 gender: smallint 性别,女是0,男是1根据身份证号查找所有未填写…...
微服务管家:NestJS 如何使用服务发现 Consul 实现高效的微服务节点管理
前言 在微服务架构中,服务发现是一项基础且关键的功能,它允许服务实例在网络中被动态发现。Consul 是一种服务网格解决方案,提供了服务发现、运行状况检查,过去和现代应用程序的连接等功能。 本教程将向您展示如何在 NestJS 框架…...
Baumer工业相机堡盟工业相机如何联合NEOAPI SDK和OpenCV实现相机图像转换为Mat图像格式(C++)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK实现相机掉线自动重连(C) Baumer工业相机Baumer工业相机的图像转换为OpenCV的Mat图像的技术背景在NEOAPI SDK里实现相机图像转换为Mat图像格式联合OpenCV实现相机图像转换为Mat图像格式测试演示图 工业相机…...
铁塔基站数字化管理监测解决方案
截至2023年10月,我国5G基站总数达321.5万个,占全国通信基站总数的28.1%。然而,随着5G基站数量的快速增长,基站的能耗问题也逐渐日益凸显,基站的用电给运营商带来了巨大的电费开支压力,降低5G基站的能耗成为…...
如何使用Python3 Boto3删除AWS CloudFormation的栈(Stacks)
文章目录 小结问题及解决有关Json文件的输入和输出使用Python3及正则表达式查找字符串包含某个子字符串使用Python3 Boto3删除AWS CloudFormation的栈(Stacks) 参考 小结 本文记录了使用Python3的Boto3包删除AWS CloudFormation的栈(Stacks&…...
差分约束算法
差分约束 差分约束系统包含 m m m个涉及 n n n个变量的差额限制条件,这些差额限制条件每个都是形式为 x i − x j ≤ b ∈ [ 1 , m ] x_i-x_j\leq b_{\in[1,m]} xi−xj≤b∈[1,m]的简单线性不等式。 通常我们要求解出一组可行解。 最短路差分约束 如果我们…...
彻底解决vue-video-player播放视频有黑边
需求 最近需要接入海康视频摄像头,然后把视频的画面接入到自己的网站系统中。以前对接过rtsp固定IP的显示视频,这次的不一样,没有了固定IP。海康的解决办法是,摄像头通过配置服务器到萤石云平台,然后购买企业版账号和…...
区域负责人常用的ChatGPT通用提示词模板
区域市场分析:如何分析区域市场的特点、竞争态势和客户需求? 区域销售策略制定:如何制定针对区域市场的销售策略,包括产品定位、价格策略、渠道策略等? 区域销售目标设定:如何设定明确的区域销售目标&…...
Java Spring boot 可變參數,以及弊端
function中 不固定的參數 public boolean sendEmail(String manFrom, String manTo,String manCc, String subject, String... msg); 必須是最後一個參數,傳值時可以多個。 sendEmail(“a.gmail”,"b.gmail","c.gmail","subject",…...
机器视觉系统选型-线阵工业相机选型
线阵相机特点: 1.线阵相机使用的线扫描传感器通常只有一行感光单元(少数彩色线阵使用三行感光单元的传感器) 2.线阵相机每次只采集一行图像; 3.线阵相机每次只输出一行图像; 4.与传统的面阵相机相比,面阵扫…...
单机开机无感全自动进入B\S架构系统
单机开机无感全自动进入B\S架构系统 标题:单机用jar包启动项目bat(批处理)不弹黑窗口,并设置开机自启,打开浏览器,访问系统。引言:在实际工作中,遇到单机部署的情况,如今…...
大一,如何成为一名fpga工程师?
1、数电(必须掌握的基础),然后进阶学模电(选学), 2、掌握HDL(HDLverilogVHDL)可以选择verilog或者VHDL,建议verilog就行。 3、掌握FPGA设计流程/原理(推…...
MyBatisPlus学习三:Service接口、代码生成器
学习教程 黑马程序员最新MybatisPlus全套视频教程,4小时快速精通mybatis-plus框架 Service接口 简介 在MyBatis-Plus框架中,Service接口的作用是为实体类提供一系列的通用CRUD(增删改查)操作方法。通常情况下,Servi…...
产品经理如何选择城市?
年底,全国性的人口大迁徙即将开始。选择城市,堪称年轻人的“二次投胎”,族望留原籍,家贫走他乡。 古人在选择城市时,主要的考量因素是家族势力,这一点放在当代,大致也成立,如果在老…...
再谈“敏捷”与“瀑布”在产品开发过程中的反思
作为一家专注于软件开发的公司《智创有术》,我们致力于为客户提供创新、高效和可靠的解决方案。通过多年的经验和专业知识,我们已经在行业内建立了良好的声誉,并赢得了客户的信任和支持。 支持各种源码,网站搭建,APP&a…...
设计模式② :交给子类
文章目录 一、前言二、Template Method 模式1. 介绍2. 应用3. 总结 三、Factory Method 模式1. 介绍2. 应用3. 总结 参考内容 一、前言 有时候不想动脑子,就懒得看源码又不像浪费时间所以会看看书,但是又记不住,所以决定开始写"抄书&qu…...
Hive 源码
hive 编译 issue Failed to execute goal com.github.os72:protoc-jar-maven-plugin:3.5.1.1:run (default) on project hive-standalone-metastore: Error resolving artifact: com.google.protobuf:protoc:2.5.0: The following artifacts could not be resolved: com.goog…...
调整几行代码,接口吞吐提升 10 倍,性能调优妙啊!
景 分析过程 总结 背景 公司的一个ToB系统,因为客户使用的也不多,没啥并发要求,就一直没有经过压测。这两天来了一个“大客户”,对并发量提出了要求:核心接口与几个重点使用场景单节点吞吐量要满足最低500/s的要求。 当时一想,500/s吞吐量还不简单。Tomcat按照100个线程…...
MACOS Atrust服务异常
MAC版Atrust服务异常 点击进入办公后出现提示其一: 核心服务未启动,部分功能存在异常,确定重新启动吗? 可能的原因: 1.上次已完全退出客户端 2.核心服务被其他程序优化禁用 点击重新启动后,出现提示&#x…...
LLM大语言模型(四):在ChatGLM3-6B中使用langchain
目录 背景准备工作工具添加LangChain 已实现工具Calculator、Weather Tool配置 自定义工具自定义kuakuawo Agent 多工具使用参考 背景 LangChain是一个用于开发由语言模型驱动的应用程序的框架。它使应用程序能够: 具有上下文意识:将语言模型与上下文源(提示指令&…...
Dubbo入门介绍和实战
1. 引言 Dubbo是一款开源的高性能、轻量级的Java RPC(远程过程调用)框架,旨在解决分布式服务之间的通信问题。本文将介绍Dubbo的基础概念、核心特性以及使用场景,包括实际示例演示。 2. 什么是Dubbo? Dubbo是阿里巴…...
如何实现无人机识别功能
无人机识别算法可以基于不同的传感器和技术,结合多种方法进行实现。以下是一些常见的无人机识别算法和技术: 视觉识别: 图像处理: 使用计算机视觉技术对无人机图像进行处理,包括特征提取、目标检测和跟踪等。深度学习&…...
Python学习笔记(四)流程控制方法
流程控制有三种方法:分支、循环、跳出 流程的控制通过布尔值来实现,分支和循环都需要对一定的条件进行判断,根据判断结果(布尔值)决定下一步要做什么 布尔值通过比较运算符、逻辑运算符来进行判断是True还是False 不…...
怎么做网站赚钱放广告/营销技巧和营销方法心得
本篇文章介绍一下OAuth2.0相关的知识点,并且手把手带大家搭建一个认证授权中心、资源服务进行OAuth2.0四种授权模式的验证,案例源码详细,一梭子带大家了解清楚。 本篇文章的案例源码项目架构为:Spring Boot Spring Cloud Alibab…...
网站360自然排名要怎么做/新闻稿发布
在iOS app 中经常会嵌套html 代码,js运行alert时会出现这个问题,见图: 提示框的title为所在目录文件夹名字: 解决方案: 用 iOS native 的uiwebview 的扩展方法来监听 js的alert 然后自定义 alert 的title #import &…...
mobile wordpress.org/社区推广
ubuntu12.04(32位)下TQ2440开发板环境搭建 Step 1.安装arm-linux-gcc交叉编译器 这里我使用的是天嵌tq2440光盘下的EABI-4.3.3_EmbedSky_20100610.tar.bz2安装包。 1、在根目录下解压EABI-4.3.3_EmbedSky_20100610.tar.bz2sudo tar -xvfEABI-4.3.3_Embe…...
回收类型网站如何做/厦门seo怎么做
2019独角兽企业重金招聘Python工程师标准>>> 写操作MongoDB比传统数据库快的根本原因是Mongo使用的内存映射技术 - 写入数据时候只要在内存里完成就可以返回给应用程序,这样并发量自然就很高。而保存到硬体的操作则在后台异步完成。 MongoDB在…...
益阳网站开发/外贸接单平台哪个最好
## 获取指定行 var row $(#stuA).datagrid(getRows)[0]; 注:stuA为table id ## 获取选中行 var row $(#stuA).datagrid(getSelected);...
塑料袋销售做哪个网站推广好/代码优化
Hexo 我的博客到目前为止,可以分为3个阶段:博客园->Octopress->Hexo 我并没有经历过经典的WordPress的阶段,考虑到买域名、租VPS的费用,及麻烦程度。 我博客园的CSS经历过两次大修改,我一直寻求一种较为Geek风格…...