JDBC(通过JAVA访问数据库)

知识点:

AUTO_INCREMENT----自动增长

PRIMARY KEY-----主键

DEFAULT CHARSET=uft8----缺省字符集

初始化中jdbc:mysql的意思是连接mysql的协议

端口是通讯连接比如mysql是3306

一:建立与数据库的连接

步骤12345
做法导入jar包初始化驱动与数据库建立联系创建statement去执行关闭数据库

注意Statement时,除了字符串要用单引号,其他都是双引号,整数和字符串两边都得加"+"号

package jbbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class tt {
	public static void main(String[] args) {
		try{
			//com.mysql.jdbc.Driver就在jar包里面
			Class.forName("com.mysql.jdbc.Driver");
			System.out.println("驱动初始化完成!");
		}catch(ClassNotFoundException e){
			e.printStackTrace();
		}
		//建立与数据库的Connection连接
		//jdbc.mysql是协议
		//characterEncoding作用是把接受的数据进行重新编码
        //使用try-with-resource的方式自动关闭连接
		try(
				Connection a=DriverManager.getConnection(
				"jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
				"root","admin");
				//创建Statement并且执行
				Statement b=a.createStatement();
				){
            for(int n=1;n<20;n++){
			String ss="insert into hero values(null,"+"'虾兵蟹 
                   将"+n+"',"+460.0f+","+90+")";
			b.execute(ss);//执行插入数据
			}
			String ss="insert into hero values(null,"+"'树神'"+","+460.0f+","+90+")";
			b.execute(ss);//执行插入数据
		}catch(SQLException e){
			e.printStackTrace();
		}
	}
}

二、增删改查

CRUD是最常见的数据库操作

CRUD
增加Create读取查询Retrieve更新Update删除Delete

操作与增加类似:

//删除
String aa="delete from hero whero id=5";
//更新
String bb="update hero set name='僵尸' whero id=10";
执行即可

查询语句有所不同

利用类import java.sql.ResultSet;

package jbbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;
public class tt {
	public static void main(String[] args) {
		try{
			//com.mysql.jdbc.Driver就在jar包里面
			Class.forName("com.mysql.jdbc.Driver");
			System.out.println("驱动初始化完成!");
		}catch(ClassNotFoundException e){
			e.printStackTrace();
		}
		//建立与数据库的Connection连接
		//jdbc.mysql是协议
		//characterEncoding作用是把接受的数据进行重新编码
		try(
				Connection a=DriverManager.getConnection(
				"jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
				"root","admin");
				//创建Statement并且执行
				Statement b=a.createStatement();
		){
			String sql="select * from hero";
			//执行查询语句,并把结果返回给ResultSet
			ResultSet rr=b.executeQuery(sql);
			while(rr.next()){
				int id=rr.getInt("id");//可以使用字段名
				String name=rr.getString(2);//也可以使用字段的顺序
				Float hp=rr.getFloat("hp");
				int damage=rr.getInt(4);
				System.out.printf("%d\t%s\t%f\t%d%n",id,name,hp,damage);
			}
		}catch(SQLException e){
			e.printStackTrace();
		}
	}
}

获取数据总数

  String cc="select count(*) from hero";
  ResultSet ccc=b.executeQuery(cc);
  int number=0;
	while(ccc.next()){
			number=ccc.getInt(1);
		}
	System.out.println("共有"+number+"数据");

三、编译Statement(preparedStatement)

和Statement一样也是用来执行sql语句的,不同的是需要根据sql语句创建PreparedStatement,除此之外还能够通过设置参数,指定相应的值,而不是Statement那样使用字符串拼接
注: 这是JAVA里唯二的基1的地方,另一个是查询语句中的ResultSet也是基1的

package jbbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class tt {
	public static void main(String[] args) {
		try{
			//com.mysql.jdbc.Driver就在jar包里面
			Class.forName("com.mysql.jdbc.Driver");
			System.out.println("驱动初始化完成!");
		}catch(ClassNotFoundException e){
			e.printStackTrace();
		}
		String sql="insert into hero value(null,?,?,?)";
		try(
				Connection a=DriverManager.getConnection(
				"jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
				"root","admin");
				//根据sql创建PreparedStatement
				PreparedStatement b=a.prepareStatement(sql);
		){
			b.setString(1, "美杜莎孙子");
			b.setFloat(2, 568.0f);
			b.setInt(3, 450);
			b.execute();
		}catch(SQLException e){
			e.printStackTrace();
		}
	}
}

PreparedStatement的优点

参数设置PreparedStatement可读性好也不易犯错;而Statement还需要字符串拼接,就比较麻烦
性能表现PreparedStatement有预编译机制性能比Statement更快
防止SQL注入式攻击PreparedStatement是参数设置就可以避免这种问题,如果数据是用户提交的

四、execute与executeUpdate的区别

相同点都可以执行增加、删除、修改,方法一样,参考第二学的查询
不同点

1、execute可以查询,executeUpdate不能执行查询语句

2、execute返回boolean类型,true表示执行的是查询语句,false表示执行的是        增删改

      executeUpdate返回的是int,表示有多少条数据受到了影响

五、特殊操作

1、获取自增长id

 在Statement通过execute或者executeUpdate执行完插入语句后,MySql会为新插入的数据分配一个自增长id。当然前提是这个表的id设置了自增长,AUTO_INCREMENT就表示自增长,代码如下

CREATE TABLE hero (
  id int(11) AUTO_INCREMENT,
  ...
}

但是无论是execute还是executeUpte都不会返回这个自增长id是多少,需要通过Statement和getGeneratedKeys获取该id

Statement.RETURN_GENERATED_KEYS参数,以确保会返回自增长ID。 通常情况下不需要加这个,有的时候需要加,所以先加上,保险一些,见如下代码

package jbbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class tt {
	public static void main(String[] args) {
		try{
			Class.forName("com.mysql.jdbc.Driver");
			System.out.println("驱动初始化完成!");
		}catch(ClassNotFoundException e){
			e.printStackTrace();
		}
		String sql="insert into hero value(null,?,?,?)";
		try(
				Connection a=DriverManager.getConnection(
				"jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8",
				"root","admin");
				//根据sql创建PreparedStatement
				PreparedStatement b=a.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
		){
			b.setString(1, "恐龙");
			b.setFloat(2, 568.0f);
			b.setInt(3, 450);
			b.execute();
			// JDBC通过getGeneratedKeys获取该id
			ResultSet rs=b.getGeneratedKeys();
			if(rs.next()){
				int id=rs.getInt(1);
				System.out.println("该id为:"+id);
			}
		}catch(SQLException e){
			e.printStackTrace();
		}
	}
}

获取表的元数据

元数据概念:和数据库服务器相关的数据,比如数据库版本,有哪些表,表有哪些字段,字段类型是什么等等,代码如下

package jbbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
public class dbm {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
       try{
    	   Class.forName("com.mysql.jdbc.Driver");
       }catch(ClassNotFoundException e){
    	   e.printStackTrace();
       }
       try(Connection c=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root","admin");){
    	   //查看数据库层面的元数据
    	   DatabaseMetaData dbmd=c.getMetaData();
    	   //获取数据库服务器产品名称
    	   System.out.println(dbmd.getDatabaseProductName());
    	   //获取数据库服务器产品版本号
    	   System.out.println(dbmd.getDatabaseProductVersion());
    	   //获取数据库服务器用作类别和表名之间的分割符
    	   System.out.println(dbmd.getCatalogSeparator());
    	   //获取驱动版本
    	   System.out.println(dbmd.getDriverVersion());
    	   System.out.println("可用的数据库名称如下:");
    	   ResultSet rs=dbmd.getCatalogs();
    	   while(rs.next()){
    		   System.out.println("数据库名称:\t"+rs.getString(1));
    	   }
       }catch(SQLException e){
    	   e.printStackTrace();
       }
	}
}

六、事务

   作用:在事务的多个操作,要么都成功要么都失败,见如下代码

   使用方法:通过 Connection对象.setAutoCommit(false);关闭自动提交

                             Connection对象.commit();进行手动提交

try(Connection c......
    Statement s=c.createStatement();){
        c.setAutoCommit(false);//关闭自动提交
        String sql1=..........;
        s.execute(sql1);
        String sql2=..........;
        s.execute(sql2);
        c.commit();//手动提交
}catch.....

注意在Mysql中,只有当表的类型是INNODB的时候才支持事务,所以需要把表的类型设置为INNODB,否则无法观察到事务,代码如下

//修改表的类型为INNODB的SQL
alter table hero  ENING=innodb;
//查看表的类型
show table status from how2java;
不过有个前提,就是当前的MYSQL服务器本身要支持INNODB,如果不支持,看 开启MYSQL INNODB的办法

七、ORM  ------对象和关系数据库的映射

ORM=Object  Relationship  Database  Mapping

简单的说就是一个对象对应数据库里的一条记录

注意的是:框架一环接一环

package jbbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import charactor.Hero;
public class YS {
	public static Hero get(int id) {
	   Hero hero =null;
       try{
    	   Class.forName("com.mysql.jdbc.Driver");
       }catch(ClassNotFoundException e){
    	   e.printStackTrace();
       }
       try(Connection c=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8","root","admin");
    		   Statement s=c.createStatement();){
    	   String sql="select * from hero where id="+id;
    	   ResultSet rs=s.executeQuery(sql);
    	   //因为id是唯一的,ResultSet最多只能有一条记录,所以使用if代替while
    	   if(rs.next()){
    		   hero=new Hero();
    		   String name=rs.getString(2);
    		   float hp=rs.getFloat("hp");
    		   int damage=rs.getInt(4);
    		   hero.name=name;
    		   hero.hp=hp;
    		   hero.damage=damage;
    		   hero.id=id;
    	   }
       }catch(SQLException e){
    	   e.printStackTrace();
       }
       return hero;
	}
	public static void main(String[]args){
		Hero h=get(22);
		System.out.println(h.name);
	}
}

八、DAO----数据访问对象

DAO=Data  Access  Object

实际上就是运用了ORM中的思路,把数据库相关的操作都封装在这个类里面,其他地方看不到JDBC的代码

package jbbc;
import java.util.List;
import charactor.Hero;
public interface DAO {
    public void add(Hero hero);
    public void update(Hero hero);
    public void delete(Hero hero);
    public void get(int id);
    public List<Hero> list();
    public List<Hero> list(int start,int count);
}

九、数据库连接池(ConnectionPoll)

与线程池类似数据库也有一个数据库连接池,不过实现思路不一样

传统方式:当有多个线程需要连接数据库并执行的话,那么每个线程就会创建一个连接,并且在                     使用完毕后关闭连接。这种方式耗时间加上一个数据库同时支持的连接总数是有限的,                   如果并发量很大就会卡顿并且后续线程发起连接就会失败。

使用池:与传统方式不同,连接池在使用之前就会创建好一定数量的连接。这个时候如果有线程                  需要连接那么就从连接池里借用而不是重新创建。使用完毕后归还供下一个线程使用。                  倘若多线程并发,其他线程就会临时等待直到有连接归还。整个过程连接不会关闭一直循环

数据库连接池原理-使用池

ConnectionPoll构造方法和初始化

1、ConnectionPool()构造方法约定了这个连接池一共有多少连接

2、在init()初始化方法中,创建了size条连接。注意,这里不能使用 try-with-resourse这种自动       关闭连接的方式,因为连接恰恰需要保持不关闭状态,供后续循环使用

3、getConnection,判断是否为空,如果是空的就wait,否则就借用一条连接出去

4、returnConnection,在使用完毕后,归还这个连接到连接池,并且在归还完毕后调用notify,通       知那些等待的线程,有新的连接可以借用了

package jbbc;
import java.util.List;
import java.util.ArrayList;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionPool {
	 List<Connection>cp=new ArrayList<Connection>();
     int size;
     public ConnectionPool(int size){
     	this.size=size;
     	init();//初始化calss变量
     }
     public void init(){
    	 //这里恰恰不能使用try-with-resource的方式,因为这些连接都需要循环,不能被自动关闭了
    	 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", "admin");
    			 cp.add(c);
    		 }
    	 }catch(ClassNotFoundException e){
    		 e.printStackTrace();
    	 }catch(SQLException e){
    		 e.printStackTrace();
    	 }
     }
     public synchronized Connection getConnection(){
    	 while(cp.isEmpty()){
    		 try{
    			 this.wait();
    		 }catch(InterruptedException e){
    			 e.printStackTrace();
    		 }
    	 }
    	 Connection c=cp.remove(0);
    	 return c;
     }
     public synchronized void returnConnection(Connection c){
    	 cp.add(c);
    	 this.notify();
     }
}

 测试类(初始化3条连接,创建100条线程,拿到连接后执行一个耗时1秒的SQL语句)

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 cp = new ConnectionPool(3);
        for (int i = 0; i < 100; i++) {
            new WorkingThread("working thread" + i, cp).start();
        }
   
    }
}
   
class WorkingThread extends Thread {
    private ConnectionPool cp;
   
    public WorkingThread(String name, ConnectionPool cp) {
        super(name);
        this.cp = cp;
    }
   
    public void run() {
        Connection c = cp.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) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        cp.returnConnection(c);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值