当前位置:网站首页>MySQL learning notes 3 - JDBC
MySQL learning notes 3 - JDBC
2022-07-04 06:16:00 【Bug No.1 quality inspector】
Catalog
JDBC brief introduction
Java Database connection ,(Java Database Connectivity, abbreviation JDBC) yes Java Language used to regulate how the client program to access the database application program interface , Provides methods such as querying and updating data in a database .
Database driven
What is database driven ? Similar to sound card drive 、 Driver.
Our program will be driven by database , Dealing with databases .
JDBC
SUN Companies to simplify the development of ( Unification of databases ) operation , Provides a (Java Operating the database ) standard ,JDBC.
These specifications are implemented by specific manufacturers .
For developers , We just need to master JDBC The interface operation of .
java.sql
javax.sql
You also need to import the database driver package
first JDBC Program
1. Create test database
CREATE DATABASE jdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci;
USE jdbcStudy;
CREATE TABLE `users`(
id INT PRIMARY KEY,
NAME VARCHAR(40),
PASSWORD VARCHAR(40),
email VARCHAR(60),
birthday DATE
);
INSERT INTO `users`(id,NAME,PASSWORD,email,birthday)
VALUES(1,'zhansan','123456','[email protected]','1980-12-04'),
(2,'lisi','123456','[email protected]','1981-12-04'),
(3,'wangwu','123456','[email protected]','1979-12-04')
2. Create a normal project
3. Import database driver
pom.xml
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
4. Write test code
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JdbcDemo {
public static void main(String[] args) throws Exception {
//1. The load driver
Class.forName("com.mysql.cj.jdbc.Driver");// Fixed writing jdbc Driver version 8.0 For before com.mysql.jdbc.Driver
//2. User information and url
//useUnicode=true&characterEncoding=utf8&&useSSL=true
//useUnicode=true Support Chinese coding ;characterEncoding=utf8 The Chinese character set is set to utf-8;useSSL=true Use secure links
//jdbc Driver version 8.0 Then add serverTimezone=UTC
String url ="jdbc:mysql://localhost:3306/jdbcstudy?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&&useSSL=true";
String name = "root";
String password = "123456";
//3. Successful connection , Returns the database object connection On behalf of the database
Connection connection= DriverManager.getConnection(url,name,password);
//4. perform SQL The object of statement perform SQL The object of
Statement statement = connection.createStatement();
//5. perform SQL The object of To carry out SQL There may be results , View return results
String sql="SELECT * FROM users";
ResultSet resultSet = statement.executeQuery(sql);// The result set returned , The result set encapsulates the results of all our queries
while(resultSet.next()){
System.out.println("ID="+resultSet.getObject("id"));
System.out.println(" full name ="+resultSet.getObject("NAME"));
System.out.println(" password ="+resultSet.getObject("PASSWORD"));
System.out.println(" mailbox ="+resultSet.getObject("email"));
System.out.println(" Birthday ="+resultSet.getObject("birthday"));
System.out.println("==================================");
}
//6. Release the connection ( Release from back to front )
resultSet.close();
statement.close();
connection.close();
}
}
JDBC Detailed explanation of each object in
Step summary :
1. The load driver
2. Connect to database DriverManager
3. Access to perform SQL The object of Statement
4. Get the returned result set
5. Release the connection
DriverManager
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");// Fixed writing
Connection connection= DriverManager.getConnection(url,name,password);
//connection On behalf of the database
// Database settings auto commit
// Transaction submission
// Transaction rollback
connection.rollback();
connection.commit();
connection.setAutoCommit();
URL
String url ="jdbc:mysql://localhost:3306/jdbcstudy?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&&useSSL=true";
//mysql Default port 3306
// agreement :// The host address : Port number / Database name ? Parameters 1& Parameters 2& Parameters 3...
//Oracle 1521
//jdbc:oralce:thin:@localhost:1521:sid
statement perform SQL The object of PrepareStatement perform SQL The object of
String sql="SELECT * FROM users";// To write Sql
statement.executeQuery();// Query operation , return ResultSet
statement.execute();// Carry out any SQL
statement.executeUpdate();// to update , Insert , Delete , Returns the number of rows affected
ResultSet The result set of the query , Encapsulates all query results
Gets the specified data type
ResultSet resultSet = statement.executeQuery(sql);// The result set returned , The result set encapsulates the results of all our queries
resultSet.getObject();// Use... Without knowing the column type
// If you know, use the specified type
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDate();
...
Traverse , The pointer
resultSet.next(); // Move to the next
resultSet.afterLast();// Move to the end
resultSet.beforeFirst();// Move to the front
resultSet.previous();// Move to the previous one
resultSet.absolute(row);// Move to specified row
Free memory
//6. Release the connection ( Release from back to front )
resultSet.close();
statement.close();
connection.close();//connection Connection takes up the most resources
statement object
JDBC Medium statement Object to send... To the database SQL sentence , Want to complete the addition, deletion, modification and query of the database , You only need to send the add, delete, change and query statement to the database through this object .
Statement Object's executeUpdate Method , Used to send add... To the database 、 Delete 、 Changed sq| sentence , executeUpdate After the execution , Will return an integer ( That is to say, the addition, deletion and modification of statements cause several rows of data in the database to change ).
Statement.executeQuery Method is used to generate a query statement to the database ,executeQuery Method to return ResultSet object .
CRUD operation -create
Use executeUpdate(String sql) Method to complete the data adding operation , Example operation :
Statement statement = connection.createStatement();
String sql = "insert into user(...) values(...)";
int num = statement.executeUpdate(sql);
if(num>0){
System.out.println(" Insert the success ");
}
CRUD operation -delete
Use executeUpdate(String sql) Method to delete data , Example operation :
Statement statement = connection.createStatement();
String sql = "delete from user where id =1";
int num = statement.executeUpdate(sql);
if(num>0){
System.out.println(" Delete successful ");
}
CURD operation -update
Use executeUpdate(String sql) Method to complete the data modification operation , Example operation :
Statement statement = connection.createStatement();
String sql = "update user set name ='' where name = ''";
int num = statement.executeUpdate(sql);
if(num>0){
System.out.println(" Modification successful ");
}
CURD operation -read
Use executeUpdate(String sql) Method to complete data query operation , Example operation :
Statement statement = connection.createStatement();
String sql = "select * from user where id =1";
ResultSet rs= statement.executeQuery(sql);
if(rs.next()){
System.out.println("");
}
Packaged as tools
First configuration file db.properties Write a good message
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&&useSSL=true
username=root
password=123456
Tool class
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null;
static {
try{
FileInputStream in = new FileInputStream("src/main/resources/db.properties");
Properties properties = new Properties();
properties.load(in);
driver=properties.getProperty("driver");
url=properties.getProperty("url");
username=properties.getProperty("username");
password=properties.getProperty("password");
//1. The driver only loads once
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//2. Get the connection
public static Connection getConnection() throws Exception{
return DriverManager.getConnection(url, username, password);
}
//3. Release resources
public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException {
if (rs != null) {
rs.close();
}
if (st != null){
st.close();
}
if(conn != null){
conn.close();
}
}
}
Use tool class ( Insert data as an example )(exectueUpdate
You can add, delete and modify three operations )
import com.cheng.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import static com.cheng.utils.JdbcUtils.getConnection;
public class TestInsert {
public static void main(String[] args){
Connection conn =null;
Statement st = null;
ResultSet rs =null;
try {
conn = getConnection();// Get the connection
st = conn.createStatement();// obtain SQL Perform object
String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`)" +
"VALUES(5,' Hello ','123456','[email protected]','2020-01-01')";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println(" Insert the success ");
}
JdbcUtils.release(conn,st,rs);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Use tool class ( Query data as an example )
import com.cheng.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import static com.cheng.utils.JdbcUtils.getConnection;
public class TestQuery {
public static void main(String[] args) throws SQLException {
Connection conn =null;
Statement st = null;
ResultSet rs =null;
try {
conn = getConnection();// Get the connection
st = conn.createStatement();// obtain SQL Perform object
String sql = "select * from users";
rs=st.executeQuery(sql);// After the query, the result set is returned
while (rs.next()){
System.out.println(rs.getString("NAME"));
}
JdbcUtils.release(conn,st,rs);
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
SQL Injection problem
sql Vulnerability , Can be attacked and result in data leakage SQL Will be stitched together or
principle , For example, the normal password query is to match the password , But add one or 1=1 Then you will think that the password query passed , because or If there is one on the left and right sides, it is considered to be established , Again because 1=1 Hang up , So the server was cheated , Think the password query passed
Example
import com.cheng.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import static com.cheng.utils.JdbcUtils.getConnection;
public class SqlInjection {
public static void main(String[] args) {
// Normal query
login(" Hello ","123456");
System.out.println("=================");
// SQL Inject
login("' OR '1=1","' OR '1=1");
}
public static void login(String name,String password){
Connection conn =null;
Statement st = null;
ResultSet rs =null;
try {
conn = getConnection();// Get the connection
st = conn.createStatement();// obtain SQL Perform object
// Normal query :SELECT * FROM users WHERE `NAME`=' Hello ' AND `PASSWORD`='123456'
// SQL Inject :SELECT * FROM users WHERE `NAME`='' OR '1=1' AND `PASSWORD`='' OR '1=1'
// That is to say SELECT * FROM users In this way, you can get all the information of the whole table
String sql = "SELECT * FROM users WHERE `NAME`='"+ name +"' AND `PASSWORD`='"+ password +"'" ;
rs=st.executeQuery(sql);// After the query, the result set is returned
while (rs.next()){
System.out.println(rs.getString("NAME"));
}
JdbcUtils.release(conn,st,rs);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
JdbcUtils.release(conn,st,rs);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
PreparedStatement object
PreparedStatement Can prevent SQL Inject , More efficient .
public class Test {
public static void main(String[] args) {
Connection connection= null;
PreparedStatement pstm=null;
try {
connection = JdbcUtils.getConnection();
//PreparedStatement prevent SQL Injection essence : Treat the parameters passed in as characters
// Suppose there are escape characters , For example, quotation marks , Will be escaped directly
// difference :
// 1. Use a question mark placeholder instead of a parameter
String sql = "insert into users(id, `NAME`, `PASSWORD`, `email`,`birthday`) values(?, ?, ?, ?, ?)";
// 2. precompile sql, First write sql Then don't execute
pstm = connection.prepareStatement(sql);
// Manual assignment
pstm.setInt(1,4);// 1 On behalf of the first question mark
pstm.setString(2," Zhang San ");
pstm.setString(3,"123123");
pstm.setString(4,"[email protected]");
pstm.setDate(5,new java.sql.Date(new Date().getTime()));// Be careful to convert to sql Of Date
// perform
int i = pstm.executeUpdate();
if (i>0){
System.out.println(" Insert the success ");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
JdbcUtils.release(connection,pstm,null);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
Output :
Hello
=================
zhansan
lisi
wangwu
Zhang San
Hello
prevent SQL Injection essence , Pass characters with “ ”, Escape characters will be escaped
Improvement examples :
import com.cheng.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) {
// Normal query
login(" Hello ","123456");
System.out.println("=================");
// SQL Inject
login("'' OR 1=1","'' OR 1=1");
}
public static void login(String username,String password) {
Connection connection = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try {
connection = JdbcUtils.getConnection();
// difference :
// 1. Use a question mark placeholder instead of a parameter
String sql = "SELECT * FROM users WHERE `NAME`=? AND `PASSWORD`=?";
// 2. precompile sql, First write sql Then don't execute
pstm = connection.prepareStatement(sql);
// Manual assignment
pstm.setString(1, username);// 1 On behalf of the first question mark
pstm.setString(2, password);
rs = pstm.executeQuery();// Be careful !!!! It's not like st.executeQuery(sql); like that , Don't write in brackets sql, Otherwise, the report will be wrong . because PreparedStatement It's precompiled ,PreparedStatement Object already contains SQL Inquire about
// After the query, the result set is returned
while (rs.next()) {
System.out.println(rs.getString("NAME"));
}
JdbcUtils.release(connection, pstm, rs);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
JdbcUtils.release(connection, pstm, rs);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
Be careful !!!!rs = pstm.executeQuery();
Unlike rs = st.executeQuery(sql);
like that , Don't write in brackets sql, Otherwise, the report will be wrong . because PreparedStatement It's precompiled ,PreparedStatement Object already contains SQL Inquire about
Output :(SQL Injection failure )
Hello
=================
Use IDEA Connect to database
Connect to database
add table
Modify data sheet :
Double click on the data table , modify , Submit
Write a query
JDBC Operational transaction
Either they all succeed , Or they all failed
ACID principle
- Atomicity : Or it's all done , Or it's not done
- Uniformity : The total number of results remains the same
- Isolation, : Multiple processes do not interfere with each other
- persistence : Once submitted, it's irreversible , Persistent to the database
The problem of isolation :
- Dirty reading : One transaction reads another transaction that is not committed
- It can't be read repeatedly : In the same business , Repeatedly read the data in the table , The watch has changed
- Virtual reading ( Fantasy reading ): In a business , Read the data inserted by others , The results read before and after are inconsistent
Code implementation
- Open transaction conn.setAutoCommit(false);
- A set of business execution completed , Commit transaction
- Can be in catch Statement , But the default failure will rollback
Create a sample database :
public class JdbcTransaction{
public static void main(String[] args) {
Connection conn =null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
// Turn off the auto submit function of the database , Open transaction
conn.setAutoCommit(false);
// Turn on transactions automatically
String sql = "update account set money = money-100 where id = 1";
ps =conn.prepareStatement(sql);
ps.executeUpdate();
String sql2 = "update account set money = money-100 where id = 2";
ps=conn.prepareStatement(sql2);
ps.executeUpdate();
// Business finished , Commit transaction
conn.commit();
System.out.println(" Successful operation ");
} catch (Exception e) {
try {
// If you fail , Rollback by default
conn.rollback();// If you fail , Roll back
System.out.println(" Failure ");
} catch (SQLException throwables) {
throwables.printStackTrace();
}
e.printStackTrace();
}finally {
try {
JdbcUtils.release(conn,ps,rs);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
Database connection pool
Traditional connection : Database connection – completion of enforcement – Release
The server repeatedly connects – Releasing will be a waste of resources
Pool technology : Prepare some resources in advance , Come and connect with the prepared
- Number of common connections :10
- Minimum connections :10( It is generally equal to the number of commonly used connections )
- maximum connection : 100( The maximum carrying capacity of the service )
- If it is greater than the maximum number of connections , Waiting in line ,
- Waiting for timeout :100ms(100ms After waiting for the link to disconnect )
Write connection pools : Implement an interface DateSource
Common open source data source implementations ( Use immediately )
The following are common in the market DateSource Implementation class of interface
- DBCP
- C3P0
- Druid: Alibaba
After using these database connection pools , We don't need to write the code to connect to the database in the project development
DBCP
needed JAR package
( Use maven Import )
pom.xml
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.7.0</version>
</dependency>
DBCP The configuration file
dbcp-config.properties
# connections setting up
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&&useSSL=true
username=root
password=123456
#<!-- Initialize connection -->
initialSize=10
# Maximum number of connections
maxActive=50
#<!-- Maximum free connection -->
maxIdle=20
#<!-- Minimum free connection -->
minIdle=5
#<!-- Timeout wait time in milliseconds 6000 millisecond /1000 be equal to 60 second -->
maxWait=60000
#JDBC The format of the connection attribute attribute attached to the driver when establishing the connection must be as follows :【 Property name =property;】
# Be careful :"user" And "password" Two attributes are explicitly passed , So there's no need to include them .
connectionProperties=useUnicode=true;characterEncoding=UTF8
# Specifies the automatic commit of connections created by the connection pool (auto-commit) state .
defaultAutoCommit=true
#driver default Specifies the read-only... Of the connection created by the connection pool (read-only) state .
# If the value is not set , be “setReadOnly” Method will not be called .( Some drivers do not support read-only mode , Such as :Informix)
defaultReadOnly=
#driver default Specify the transaction level of the connection created by the connection pool (TransactionIsolation).
# The available values are one of the following :( Details visible javadoc.)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
Tool class
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
public class Dbcp {
private static DataSource dataSource = null;
static {
try{
FileInputStream in = new FileInputStream("src/main/resources/dbcpconfig.properties");
Properties properties = new Properties();
properties.load(in);
// 1. create data source Factory mode ——> establish
dataSource = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
// 2. Get the connection
public static Connection getConnection() throws Exception{
return dataSource.getConnection(); // Get the connection from the data source
}
// 3. Release resources
public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException {
if (rs != null) {
rs.close();
}
if (st != null){
st.close();
}
if(conn != null){
conn.close();
}
}
}
Test code
import com.cheng.utils.Dbcp;
import java.sql.*;
public class DbcpTest {
public static void main(String[] args) throws SQLException {
Connection conn =null;
PreparedStatement ps = null;
ResultSet rs =null;
try {
conn = Dbcp.getConnection();
String sql = "select * from users";
ps=conn.prepareStatement(sql);
rs=ps.executeQuery();
while (rs.next()){
System.out.println(rs.getString("NAME"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
Dbcp.release(conn,ps,rs);
}
}
}
C3P0
needed JAR package
( Use maven Import )
pom.xml
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.4</version>
</dependency>
C3P0 The configuration file
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- If in code "ComboPooledDataSource ds=new ComboPooledDataSource();" This means that you are using c3p0 Default ( Default )-->
<!-- c3p0 Default ( Default ) To configure -->
<default-config>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&&useSSL=true</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<!-- If in code "ComboPooledDataSource ds=new ComboPooledDataSource("s1");" This means that you are using s1 Configuration parameters )-->
<named-config name="s1">
</named-config>
</c3p0-config>
in addition , You can use code to configure parameters
// You can use code to configure parameters
dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("");
dataSource.setJdbcUrl("");
dataSource.setUser("");
dataSource.setPassword("");
dataSource.setMaxPoolSize(100);
Tool class
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class C3p0 {
private static ComboPooledDataSource dataSource = null;
static {
try{
// create data source
dataSource = new ComboPooledDataSource();
} catch (Exception e) {
e.printStackTrace();
}
}
// 2. Get the connection because getConnection() It's the interface method So the following is DBCP Nothing has to change
public static Connection getConnection() throws Exception{
return dataSource.getConnection(); // Get the connection from the data source
}
// 3. Release resources
public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException {
if (rs != null) {
rs.close();
}
if (st != null){
st.close();
}
if(conn != null){
conn.close();
}
}
}
Test code
import com.cheng.utils.C3p0;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class C3p0Test {
public static void main(String[] args) throws SQLException {
Connection conn =null;
PreparedStatement ps = null;
ResultSet rs =null;
try {
conn = C3p0.getConnection();
String sql = "select * from users";
ps=conn.prepareStatement(sql);
rs=ps.executeQuery();
while (rs.next()){
System.out.println(rs.getString("NAME"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
C3p0.release(conn,ps,rs);
}
}
}
Conclusion
No matter what data source is used , The essence is unchangeable ,DateSource The interface will not change , The method won't change , Because these open source data sources are DateSource Interface implementation .
边栏推荐
猜你喜欢
体验碎周报第 102 期(2022.7.4)
检漏继电器JY82-2P
js arguments参数使用和详解
AWT常用组件、FileDialog文件选择框
My NVIDIA developer journey - optimizing graphics card performance
How much computing power does transformer have
Halcon image calibration enables subsequent image processing to become the same as the template image
Design and implementation of redis 7.0 multi part AOF
Learning multi-level structural information for small organ segmentation
JS flattened array of number shape structure
随机推荐
fastjson
Tsinghua University product: penalty gradient norm improves generalization of deep learning model
HMS v1.0 appointment. PHP editid parameter SQL injection vulnerability (cve-2022-25491)
How to help others effectively
Kubernets first meeting
Design and implementation of tcp/ip series overview
After the festival, a large number of people change careers. Is it still time to be 30? Listen to the experience of the past people
How to implement cross domain requests
How to choose the middle-aged crisis of the testing post? Stick to it or find another way out? See below
注释与注解
Input displays the currently selected picture
How to get the parent node of all nodes in El tree
Arcpy 利用updatelayer函数改变图层的符号系统
One click filtering to select Baidu online disk files
Qt发布多语言国际化翻译
The difference between PX EM rem
C语言中的函数(详解)
报错cvc-complex-type.2.4.a: 发现了以元素 ‘base-extension‘ 开头的无效内容。应以 ‘{layoutlib}‘ 之一开头。
JSON Web Token----JWT和傳統session登錄認證對比
How to realize multi account login of video platform members