目录
一.MySQL 下载和 MySQL 驱动下载
MySQL是应用最广泛的开源关系数据库。
下载链接:https://dev.mysql.com/downloads/mysql/
下载 Connector 驱动:https://dev.mysql.com/downloads/connector/j/
选择 Platform Independent
二.MySQL 命令行
进入MySQL命令行:
mysql -u root -p
(输入密码)
切换到test数据库:
mysql> use test;
查看数据库表:
mysql> show tables;
三.MySQL特殊操作
1.excute 和 excuteUpdate 区别
2.获取自增 ID
3.获取元数据
1.excute 和 excuteUpdate 和 excuteQuery区别
executeQuery(String sql)
执行select语句,它返回的是查询后得到记录集(resultset)。
executeUpdate(String sql)
执行update,insert,delete语句,它返回的是语句执行后说影响到的记录条数(int)
execute(String sql)
执行任何sql语句,也就是前两者之和。
当执行结果是查询语句时,返回true,可以通过getResultSet方法获取结果;
当执行的是update,delete,insert语句时,返回false,可以通过getUpdateCount方法获取更新的记录数量。
2.获取自增 ID
public int add(){
Connection conn=null;
PreparedStatement ps=null;
try {
conn = ConnUtil.getConnection();
ps = conn.prepareStatement("insert student(name,age)values(?,?)", Statement.RETURN_GENERATED_KEYS);
ps.setString(1,"joe");
ps.setInt(2,23);
int i = ps.executeUpdate();
// 在执行完插入语句后,MySQL会为新插入的数据分配一个自增长id
// JDBC通过getGeneratedKeys获取该id
ResultSet rs=ps.getGeneratedKeys();
while(rs.next()){
int id=rs.getInt(1);
System.out.println("自增 id:"+id);
}
return i;
}catch (SQLException e){
e.printStackTrace();
}finally {
ConnUtil.close(ps,conn);
}
return 0;
}
3.获取元数据
public void getDataBaseMetaData(){
Connection conn=null;
try{
conn=ConnUtil.getConnection();
DatabaseMetaData dbmd=conn.getMetaData();
// 获取数据库服务器产品名称
System.out.println("数据库产品名称:\t"+dbmd.getDatabaseProductName());
// 获取数据库服务器产品版本号
System.out.println("数据库产品版本:\t"+dbmd.getDatabaseProductVersion());
// 获取数据库服务器用作类别和表名之间的分隔符 如test.user
System.out.println("数据库和表分隔符:\t"+dbmd.getCatalogSeparator());
// 获取驱动版本
System.out.println("驱动版本:\t"+dbmd.getDriverVersion());
System.out.println("可用的数据库列表:");
// 获取数据库名称
ResultSet rs = dbmd.getCatalogs();
while (rs.next()) {
System.out.println("数据库名称:\t"+rs.getString(1));
}
}catch (Exception e){
e.printStackTrace();
}finally {
ConnUtil.close(conn);
}
}
四.MySQL常用操作 增删改查
public class ConnUtil {
public static Connection getConnection(){
Connection connection;
try{
Class.forName("com.mysql.cj.jdbc.Driver");
connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/students?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT&user=root&password=12345678");
return connection;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
public static void close(Object ...objects){
try {
for (Object object : objects) {
if (object instanceof ResultSet) {
ResultSet rs = (ResultSet) object;
rs.close();
} else if (object instanceof Statement) {
Statement statement = (Statement) object;
statement.close();
} else if (object instanceof Connection) {
Connection conn = (Connection) object;
conn.close();
}
}
}catch (SQLException e){
e.printStackTrace();
}
}
}
public class StudentDao {
public int add(){
Connection conn=null;
PreparedStatement ps=null;
try {
conn = ConnUtil.getConnection();
ps = conn.prepareStatement("insert student(name,age)values(?,?)", Statement.RETURN_GENERATED_KEYS);
ps.setString(1,"joe");
ps.setInt(2,23);
int i = ps.executeUpdate();
ResultSet rs=ps.getGeneratedKeys();
while(rs.next()){
int id=rs.getInt(1);
System.out.println("自增 id:"+id);
}
return i;
}catch (SQLException e){
e.printStackTrace();
}finally {
ConnUtil.close(ps,conn);
}
return 0;
}
public int delete(){
Connection conn=null;
PreparedStatement ps=null;
try {
conn=ConnUtil.getConnection();
ps=conn.prepareStatement("delete from student where id=?");
ps.setInt(1,2);
int i=ps.executeUpdate();
return i;
}catch (SQLException e){
e.printStackTrace();
}finally {
ConnUtil.close(ps,conn);
}
return 0;
}
public int update(){
Connection conn=null;
PreparedStatement ps=null;
try {
conn=ConnUtil.getConnection();
ps=conn.prepareStatement("update student set name=?,age=? where id=?");
ps.setString(1,"joe1");
ps.setInt(2,24);
ps.setInt(3,1);
int i=ps.executeUpdate();
return i;
}catch (SQLException e){
e.printStackTrace();
}finally {
ConnUtil.close(ps,conn);
}
return 0;
}
public void get(){
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
try {
conn=ConnUtil.getConnection();
ps=conn.prepareStatement("select * from student ");
rs=ps.executeQuery();
while(rs.next()){
int id=rs.getInt("id");
String name=rs.getString("name");
int age=rs.getInt("age");
System.out.println("id="+id+" name="+name+" age="+age);
}
}catch (SQLException e){
e.printStackTrace();
}finally {
ConnUtil.close(rs,ps,conn);
}
}
public void getDataBaseMetaData(){
Connection conn=null;
try{
conn=ConnUtil.getConnection();
DatabaseMetaData dbmd=conn.getMetaData();
// 获取数据库服务器产品名称
System.out.println("数据库产品名称:\t"+dbmd.getDatabaseProductName());
// 获取数据库服务器产品版本号
System.out.println("数据库产品版本:\t"+dbmd.getDatabaseProductVersion());
// 获取数据库服务器用作类别和表名之间的分隔符 如test.user
System.out.println("数据库和表分隔符:\t"+dbmd.getCatalogSeparator());
// 获取驱动版本
System.out.println("驱动版本:\t"+dbmd.getDriverVersion());
System.out.println("可用的数据库列表:");
// 获取数据库名称
ResultSet rs = dbmd.getCatalogs();
while (rs.next()) {
System.out.println("数据库名称:\t"+rs.getString(1));
}
}catch (Exception e){
e.printStackTrace();
}finally {
ConnUtil.close(conn);
}
}
}
五.MySQL 事务
在MySQL中,只有当表的类型是INNODB的时候,才支持事务,所以需要把表的类型设置为INNODB,否则无法观察到事务.
修改表的类型为INNODB的SQL:alter table student ENGINE = innodb;
查看表的类型的SQL show table status from student;
//conn.setAutoCommit(false); 将自动提交设置为 false
//conn.commit();手动提交操作
//conn.rollback();出现错误时回滚
public int add(){
Connection conn=null;
PreparedStatement ps=null;
try {
conn = ConnUtil.getConnection();
conn.setAutoCommit(false);
ps = conn.prepareStatement("insert student(name,age)values(?,?)", Statement.RETURN_GENERATED_KEYS);
ps.setString(1,"joe");
ps.setInt(2,23);
int i = ps.executeUpdate();
int test=5/0;
conn.commit();
ResultSet rs=ps.getGeneratedKeys();
while(rs.next()){
int id=rs.getInt(1);
System.out.println("自增 id:"+id);
}
return i;
}catch ( Exception e){
e.printStackTrace();
try {
System.out.println("进行了回滚操作");
conn.rollback();
}catch (Exception ex){
ex.printStackTrace();
}
}finally {
ConnUtil.close(ps,conn);
}
return 0;
}
4.JDBC事务
数据库事务(Transaction)具有ACID特性:
Atomicity:原子性
Consistency:一致性
Isolation:隔离性
Durability:持久性
JDBC提供了事务的支持
Isolation Level | Dirty Read | Non Repeatable Read | Phantom Read |
---|---|---|---|
Read Uncommitted | Y | Y | Y |
Read Committed | Y | Y | |
Repeatable Read | Y | ||
Serializable |
六.MySQL 数据库连接池
1.不使用数据库连接池
2.使用数据库连接池
3.自己写数据库连接池
1.不使用数据库连接池
当有多个线程,每个线程都需要连接数据库执行SQL语句的话,那么每个线程都会创建一个连接,并且在使用完毕后,关闭连接。
创建连接和关闭连接的过程也是比较消耗时间的,当多线程并发的时候,系统就会变得很卡顿。
同时,一个数据库同时支持的连接总数也是有限的,如果多线程并发量很大,那么数据库连接的总数就会被消耗光,后续线程发起的数据库连接就会失败。
2.使用数据库连接池
与传统方式不同,连接池在使用之前,就会创建好一定数量的连接。如果有任何线程需要使用连接,那么就从连接池里面借用,而不是自己重新创建. 使用完毕后,又把这个连接归还给连接池供下一次或者其他线程使用。倘若发生多线程并发情况,连接池里的连接被借用光了,那么其他线程就会临时等待,直到有连接被归还回来,再继续使用。整个过程,这些连接都不会被关闭,而是不断的被循环使用,从而节约了启动和关闭连接的时间。
3.自己写数据库连接池
public class ConnPool {
List<Connection> lists=new ArrayList<Connection>();
private int size;
public ConnPool(int size){
this.size=size;
init();
}
public void init(){
try{
Class.forName("com.mysql.cj.jdbc.Driver");
for(int i=0;i<size;i++){
Connection connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/students?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT&user=root&password=12345678");
lists.add(connection);
}
}catch (Exception e){
e.printStackTrace();
}
}
public synchronized Connection getConn(){
while (lists.isEmpty()){
try {
this.wait();
}catch (Exception e){
e.printStackTrace();
}
}
Connection connection=lists.remove(0);
return connection;
}
public synchronized void returnConn(Connection conn){
lists.add(conn);
this.notifyAll();
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
}
public class WorkThread extends Thread {
private ConnPool connPool;
private String name;
public WorkThread(String name,ConnPool connPool){
super(name);
this.connPool=connPool;
}
@Override
public void run() {
Connection connection = connPool.getConn();
System.out.println(this.getName() + " 获得一个链接并开始工作"+connection.toString());
try(Statement s= connection.createStatement()){
Thread.sleep(1000);//模拟时耗1秒的数据库SQL语句
//s.executeQuery("select* from student");
}catch (Exception e){
e.printStackTrace();
}
connPool.returnConn(connection);
}
public ConnPool getConnPool() {
return connPool;
}
public void setConnPool(ConnPool connPool) {
this.connPool = connPool;
}
}
首先初始化一个有5条连接的数据库连接池
然后创建100个线程,每个线程都会从连接池中借用连接,并且在借用之后,归还连接。 拿到连接之后,执行一个耗时1秒的SQL语句。
public static void main(String[] args){
ConnPool pool=new ConnPool(5);
for (int i=0;i<100;i++){
new WorkThread("working thread"+i,pool).start();
}
}