Java---JDBC入门

JDBC (Java DataBase Connection) 是通过JAVA访问数据库。MySQL-JDBC驱动包下载地址
所用到的数据库基于该篇博文。

JDBC的Hello World

导入MySQL-JDBC驱动包:
在这里插入图片描述

package jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class TestJDBC {
    public static void main(String[] args) {
 
        Connection connection = null;
        Statement statement = null;
        try {
        	// 1. 注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 2. 获取连接
            connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8", "root",
                    "123456");
            // 3. 创建Statement
            statement = connection.createStatement();
            // 4. 书写SQL
            String sql = "insert into hero values(null," + "'提莫'" + "," + 313.0f + "," + 50 + ")";
            // 5. 执行SQL
            statement.execute(sql);
 
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            // 6. 关闭资源
            // 6.1 先关闭Statement
            if (statement != null)
                try {
                	statement.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            // 6.2 后关闭Connection
            if (connection != null)
                try {
                	connection.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }
    }
}

这个示例代码是新增数据,如果删除数据或更新数据,只需要更改对应的SQL语句即可,下面重点介绍查找数据。

查询数据

  1. 查询所有:
package jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestJDBC {
	public static void main(String[] args) {

		Connection connection = null;
		Statement statement = null;
		try {
			// 1. 注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			// 2. 获取连接
			connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
					"root", "123456");
			// 3. 创建Statement
			statement = connection.createStatement();
			// 4. 书写SQL
			String sql = "select * from hero";
			// 5. 执行SQL
			ResultSet rs = statement.executeQuery(sql);
			while (rs.next()) {
				int id = rs.getInt("id"); // 可以使用字段名
				String name = rs.getString(2); // 或使用字段顺序
				float hp = rs.getFloat("hp");
				int damage = rs.getInt("damage");
				System.out.printf("%d\t%s\t%f\t%d\n", id, name, hp, damage);
			}
			rs.close(); // 这句非必须,因为Statement关闭的时候,ResultSet随之关闭。
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			// 6. 关闭资源
			// 6.1 先关闭Statement
			if (statement != null)
				try {
					statement.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			// 6.2 后关闭Connection
			if (connection != null)
				try {
					connection.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
	}
}

  1. 查询总数:
package jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestJDBC {
	public static void main(String[] args) {

		Connection connection = null;
		Statement statement = null;
		try {
			// 1. 注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			// 2. 获取连接
			connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
					"root", "123456");
			// 3. 创建Statement
			statement = connection.createStatement();
			// 4. 书写SQL
			String sql = "select count(*) from hero";
			// 5. 执行SQL
			ResultSet rs = statement.executeQuery(sql);
			int total = -1;
			while (rs.next()) {
				total = rs.getInt(1);
			}
			System.out.printf("total = %d\n", total);
			rs.close(); // 这句非必须,因为Statement关闭的时候,ResultSet随之关闭。
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			// 6. 关闭资源
			// 6.1 先关闭Statement
			if (statement != null)
				try {
					statement.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			// 6.2 后关闭Connection
			if (connection != null)
				try {
					connection.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
	}
}

  1. 查询用户名和密码是否正确:
CREATE TABLE user (
  id int(11) AUTO_INCREMENT,
  name varchar(30) ,
  password varchar(30),
  PRIMARY KEY (id)
) ;
insert into user values(null,'name1','password1');
package jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestJDBC {
	public static void main(String[] args) {

		Connection connection = null;
		Statement statement = null;
		try {
			// 1. 注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			// 2. 获取连接
			connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
					"root", "123456");
			// 3. 创建Statement
			statement = connection.createStatement();
			String name = "name1";
			String password = "password1";
			// 4. 书写SQL
			String sql = "select * from user where name = '"+name+"' and password = '"+password+"'";
			// 5. 执行SQL
			ResultSet rs = statement.executeQuery(sql);
			if(rs.next()) {
				System.out.printf("Congratulations!");
			} else {
				System.out.printf("用户名或密码错误!");
			}
			rs.close(); // 这句非必须,因为Statement关闭的时候,ResultSet随之关闭。
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			// 6. 关闭资源
			// 6.1 先关闭Statement
			if (statement != null)
				try {
					statement.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			// 6.2 后关闭Connection
			if (connection != null)
				try {
					connection.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
	}
}

PreparedStatement

PreparedStatement比Statement有很多优点。

  1. 参数设置方便,不需要像Statement拼接字符串。可读性可维护性好。
package jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

public class TestJDBC {
	public static void main(String[] args) {

		Connection connection = null;
		PreparedStatement ps = null;
		try {
			// 1. 注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			// 2. 获取连接
			connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
					"root", "123456");
			// 3. 书写SQL
			String sql = "insert into hero values(null, ?, ?, ?)";
			// 4. 创建PreparedStatement
			ps = connection.prepareStatement(sql);
			ps.setString(1, "悟空2");
			ps.setFloat(2, 20f);
			ps.setInt(3, 209);
			// 5. 执行SQL
			ps.execute();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			// 6. 关闭资源
			// 6.1 先关闭Statement
			if (ps != null)
				try {
					ps.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			// 6.2 后关闭Connection
			if (connection != null)
				try {
					connection.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
	}
}
  1. 有预编译功能,速度快。An object that represents a precompiled SQL statement. A SQL statement is precompiled and stored in a PreparedStatement object. This object can then be used to efficiently execute this statement multiple times.而Statement每次都需要数据库编译SQL语句。
  2. 防止SQL注入攻击。如下语句拼接字符串后送到数据库再进行编译,就形成了这条语句select * from hero where name = '盖伦' OR 1=1,由于1=1恒成立,就相当于select * from hero,查询所有,如果这个表很大,就会导致数据库负载变的很高,响应很慢。而PreparedStatement设置参数,预编译,形成的SQL语句是select * from hero where name = "'盖伦' OR 1=1"!!
String name = "'盖伦' OR 1=1";
String sql0 = "select * from hero where name = " + name; //+拼接字符串效率很低

execute() 和 executeUpdate()

在这里插入图片描述
在这里插入图片描述
都可以进行增删改,前者返回boolean类型(操作是否成功),后者返回int类型(影响的记录数)。而execute还可以查,查的结果可调用getResultSet得到。

插入数据获取自增ID

execute() 和 executeUpdate()进行插入操作后,分别返回boolean类型和int类型,并没有返回对应记录的自增ID,要想得到可以如下做。

PreparedStatement ps = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);  
// 执行SQL之后
ResultSet rs = ps.getGeneratedKeys();

获取数据库元数据

package jdbc;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestJDBC {
	public static void main(String[] args) {

		Connection connection = null;
		try {
			// 1. 注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			// 2. 获取连接
			connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
					"root", "123456");
			DatabaseMetaData dbmd = connection.getMetaData();
            System.out.println("数据库服务器产品名称:\t"+dbmd.getDatabaseProductName());
            System.out.println("数据库产品版本:\t"+dbmd.getDatabaseProductVersion());
            System.out.println("数据库和表分隔符:\t"+dbmd.getCatalogSeparator()); // 如test.user
            System.out.println("驱动版本:\t"+dbmd.getDriverVersion());
            System.out.println("可用的数据库列表:");

            ResultSet rs = dbmd.getCatalogs();
            while (rs.next()) {
                System.out.println(rs.getString(1));
            }
            rs.close();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (connection != null){
				try {
					connection.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}

在这里插入图片描述

事务

MySQL中InnoDB存储引擎支持事务,MyISAM等不支持事务。
在这里插入图片描述

  1. 不用事务
package jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class TestJDBC {
	public static void main(String[] args) {

		Connection connection = null;
		Statement statement = null;
		try {
			// 1. 注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			// 2. 获取连接
			connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
					"root", "123456");
			// 3. 书写SQL
			String sql1 = "update hero set hp = hp + 1 where id = 1"; // 执行无误
			String sql2 = "updata hero set hp = hp - 1 where id = 1"; // update写错,执行错误
			// 4. 创建PreparedStatement
			statement = connection.createStatement();
			// 5. 执行SQL
			statement.execute(sql1);
			statement.execute(sql2);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			// 6. 关闭资源
			if(statement != null){
				try {
					statement.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if (connection != null){
				try {
					connection.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}

在这里插入图片描述
2. 使用事务

package jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class TestJDBC {
	public static void main(String[] args) {

		Connection connection = null;
		Statement statement = null;
		try {
			// 1. 注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			// 2. 获取连接
			connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
					"root", "123456");
			
			connection.setAutoCommit(false);
			
			// 3. 书写SQL
			String sql1 = "update hero set hp = hp + 1 where id = 1"; // 执行无误
			String sql2 = "updata hero set hp = hp - 1 where id = 1"; // update写错,执行错误
			// 4. 创建PreparedStatement
			statement = connection.createStatement();
			// 5. 执行SQL
			statement.execute(sql1);
			statement.execute(sql2);
		} catch (Exception e) {
			e.printStackTrace();
			try {
				connection.rollback(); // 回滚
			} catch (SQLException ex) {
				e.printStackTrace();
			}
		} finally {
			try {
				connection.commit(); // 提交事务
			} catch (SQLException e) {
				e.printStackTrace();
			}
			// 6. 关闭资源
			if(statement != null){
				try {
					statement.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (connection != null){
				try {
					connection.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

数据库连接池

当有多个线程都需要连接数据库执行SQL语句时,都会创建数据库连接,并且在使用完毕后,关闭连接。创建连接和关闭连接的过程是比较消耗时间的,当多线程并发的时候,系统就会变得很卡顿。
连接池在使用之前,就会创建好一定数量的连接。如果有任何线程需要使用连接,就从连接池里面借用,而不是自己重新创建。使用完毕后,又把这个连接归还给连接池供下一次或者其他线程使用。倘若连接池里的连接被借用光了,就会临时等待,直到有连接被归还回来,再继续使用。整个过程,这些连接都不会被关闭,而是不断的被循环使用,从而节约了启动和关闭连接的时间。

ConnectionPool.java

package jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
  
public class ConnectionPool {
  
    private List<Connection> connections = new ArrayList<Connection>();
    private int size;
  
    public ConnectionPool(int size) {
        this.size = size;
        init();
    }
  
    public void init() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            for (int i = 0; i < size; i++) {
                Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8", "root", "123456");
                connections.add(c);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
  
    public synchronized Connection getConnection() {
        while (connections.isEmpty()) {
            try {
            	// System.out.println(Thread.currentThread().getName() + " waiting...");
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Connection connection = connections.remove(0);
        return connection;
    }
  
    public synchronized void returnConnection(Connection connection) {
    	connections.add(connection);
        this.notifyAll();
    }
  
}

TestConnectionPool.java

package jdbc;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
 
import jdbc.ConnectionPool;
   
public class TestConnectionPool {
   
    public static void main(String[] args) {
        ConnectionPool connectionPool = new ConnectionPool(3);
        for (int i = 0; i < 100; i++) {
            new WorkingThread("working thread" + i, connectionPool).start();
        }
   
    }
}
   
class WorkingThread extends Thread {
    private ConnectionPool connectionPool;
   
    public WorkingThread(String name, ConnectionPool connectionPool) {
        super(name);
        this.connectionPool = connectionPool;
    }
   
    public void run() {
        Connection c = connectionPool.getConnection();
        System.out.println(this.getName()+ ":\t 获取了一根连接,并开始工作"  );
        try (Statement st = c.createStatement();){
             
            // 模拟耗时1秒的SQL语句
            Thread.sleep(1000);
            st.execute("select * from hero");
   
        } catch (SQLException | InterruptedException e) {
            e.printStackTrace();
        }
        connectionPool.returnConnection(c);
    }
}

参考资料

[1] How2J
[2] 《疯狂Java讲义(第4版)》 李刚
[3] 《Java核心技术 卷I》
[4] 《Java核心技术 卷II》

发布了323 篇原创文章 · 获赞 193 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/ccnuacmhdu/article/details/104031383