本人目前是某211的大二在校生,热衷于“倒腾”关于Java Web。感受接触到的东西越多,越以为对于之前学过的知识的力不从心,恰好遇上五一假期,开了一个关于本身的小菜鸟博客来记录并总结以往学过的知识。今天,咱们来谈谈JDBC。java
JDBC全称为::Java Data Base Connectivity,它是能够执行SQL语句的Java API。mysql
换句话说:JDBC实际上是官方(sun公司)定义的一套操做全部关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。咱们可使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。sql
一、首先,建立一个lib目录,里面导入驱动资源jar包数据库
二、编程
1 /** 2 2 * 示例:执行update操做 3 3 */ 4 4 public static void main(String[] args) { 5 5 String driver="com.mysql.cj.jdbc.Driver"; 6 6 String url="jdbc:mysql://127.0.0.1:3306/spj?&useSSL=false&serverTimezone=UTC"; 7 7 String user="root";//mysql用户名 8 8 String password="123456";//密码 9 9 Statement stat =null;//初始化 10 10 Connection conn =null;//初始化 11 11 try { 12 12 //注册驱动 13 13 Class.forName(driver); 14 14 //获取数据库链接对象 15 15 conn= DriverManager.getConnection(url, user, password); 16 16 //定义要执行的sql语句 17 17 String sql="update user set username = 'ycj' where id=1"; 18 18 //获取执行sql的对象 Statement 19 19 stat=conn.createStatement(); 20 20 int i = stat.executeUpdate(sql);//影响到的行数 21 21 System.out.println(i); 22 22 if(i>0) 23 23 System.out.println("sucessful"); 24 24 else 25 25 System.out.println("Fail"); 26 26 } catch (ClassNotFoundException e) { 27 27 e.printStackTrace(); 28 28 }catch (SQLException e) 29 29 { 30 30 e.printStackTrace(); 31 31 }finally { 32 32 if(stat!=null) { 33 33 try { 34 34 stat.close(); 35 35 } catch (SQLException e) { 36 36 e.printStackTrace(); 37 37 } 38 38 } 39 39 if(conn!=null) { 40 40 try { 41 41 conn.close(); 42 42 } catch (SQLException e) { 43 43 e.printStackTrace(); 44 44 } 45 45 } 46 46 } 47 47 }
对于高版本的数据库(本人使用的时MySQL 8.XXX版本)须要强制SSL的使用,即便不使用,也须要在定义URL时显式的指出:useSSL=false
,并且须要指定时区:serverTimezone=UTC
,不然会抛出SQLException。服务器
DriverManager:驱动管理对象app
*功能:框架
注册驱动:告诉程序该使用哪个数据库驱动jaride
static void registerDriver(Driver driver)
注册与给定的驱动程序 DriverManager 。函数
写代码使用: Class.forName("com.mysql.cj.jdbc.Driver");
*须要注意的是:mysql 5以后的驱动包能够省略注册驱动步骤
。*
获取数据库链接:
* 方法:
static Connection getConnection(String url, String user, String password)
* 参数:
* url:指定链接的路径
* 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
* 例子:jdbc:mysql://localhost:3306/spj
* 细节:若是链接的是本机mysql服务器,而且mysql服务默认端口是3306,则url能够简写为:jdbc:mysql:///数据库名称
* user:用户名
* password:密码
Connection:数据库链接对象,客户端与数据库全部的交互都是经过此对象完成。
功能:
1. 获取执行sql 的对象
Statement createStatement()
PreparedStatement prepareStatement(String sql)
2. 管理事务:
* 开启事务:
setAutoCommit(boolean autoCommit)
调用该方法设置参数为false,即开启事务
* 提交事务:
commit()
* 回滚事务:
rollback()
Statement:执行sql的对象
执行sql的方法:
1.
boolean execute(String sql)
能够执行任意的sql 了解
2.
int executeUpdate(String sql)
执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句
* 返回值:影响的行数,能够经过这个影响的行数判断DML语句是否执行成功
返回值>0的则执行成功,反之,则失败。
3.
ResultSet executeQuery(String sql)
执行DQL(select)语句
ResultSet:结果集对象,封装查询结果,当Statement对象执行executeQuery()时,会返回一个ResultSet对象。
方法:
* boolean next(): 游标向下移动一行,判断当前行是不是最后一行末尾(是否有数据),若是是,则返回false,若是不是则返回true
* getXxx(参数):获取数据
* Xxx:表明数据类型 如: int getInt() , String getString()
* 参数:
1. int:表明列的编号,从1开始 如: getString(1)
2. String:表明列名称。 如: getDouble("balance")
注意:
* 使用步骤:
1. 游标向下移动一行
2. 判断是否有数据
3. 获取数据
1 /** 2 *Result的使用 3 */ 4 public static void main(String[] args) { 5 String driver = "com.mysql.cj.jdbc.Driver"; 6 String url = "jdbc:mysql://127.0.0.1:3306/spj?&useSSL=false&serverTimezone=UTC"; 7 String user = "root"; 8 String password = "123456"; 9 Statement stat = null; 10 Connection conn = null; 11 ResultSet rs =null; 12 try { 13 Class.forName(driver); 14 conn = DriverManager.getConnection(url, user, password); 15 String sql = "select * from s"; 16 stat = conn.createStatement(); 17 rs = stat.executeQuery(sql); 18 19 //循环遍历,打印出表中的每个数据 20 while(rs.next()) 21 { 22 String sno = rs.getString("sno"); 23 String sname = rs.getString("Sname"); 24 int status = rs.getInt("STATUS"); 25 System.out.println(sno+"---"+sname+"---"+status); 26 } 27 28 } catch (ClassNotFoundException | SQLException e) { 29 e.printStackTrace(); 30 } finally { 31 if (rs != null) { 32 try { 33 rs.close(); 34 } catch (SQLException e) { 35 e.printStackTrace(); 36 } 37 } 38 if (stat != null) { 39 try { 40 stat.close(); 41 } catch (SQLException e) { 42 e.printStackTrace(); 43 } 44 } 45 if (conn != null) { 46 try { 47 conn.close(); 48 } catch (SQLException e) { 49 e.printStackTrace(); 50 } 51 } 52 } 53 }
PreparedStatement:执行sql的对象,继承Statement对象,功能更强大,使用起来更简单。
Statement对象编译SQL语句时,若是SQL语句有变量,就须要使用分隔符来隔开,若是变量很是多,就会使SQL变得很是复杂。PreparedStatement可使用占位符 ?来简化sql的编写
Statement会频繁编译SQL。
PreparedStatement可对SQL进行预编译,提升效率,预编译的SQL存储在PreparedStatement对象中
PreparedStatement能够防止sql注入问题。【Statement经过分隔符'++',编写永等式,能够不须要密码就进入数据库】
那咱们如何使用PreparedStatement呢?
咱们以一个令用户输入用户名和密码的案例来演示一下,数据库已经存储好了一些用户名和密码的键值对。
1 public boolean login(String username, String password) { 2 if (username == null || password == null) { 3 return false; 4 } 5 //链接数据库判断是否登陆成功 6 Connection conn = null; 7 PreparedStatement stmt = null; 8 ResultSet rs = null; 9 10 try { 11 conn = Demo01JdbcUtils.getConnection();//使用工具类 12 String sql = "select * from user where username = ? and password =? "; 13 stmt = conn.prepareStatement(sql); 14 stmt.setString(1,username); 15 stmt.setString(2,password); 16 rs = stmt.executeQuery(); 17 return rs.next();//若是有下一行,返回true 18 19 } catch (SQLException e) { 20 e.printStackTrace(); 21 } finally { 22 Demo01JdbcUtils.close(rs, stmt, conn);//使用工具类 23 } 24 return false; 25 } 26
能够看到除了定义sql语句时使用了占位符,以及给占位符变量赋值之外,其余操做都是同样的。(工具类咱们以后再说)
定义sql
\ * 注意:sql的参数使用?做为占位符。
如:select * from user where username = ? and password = ?;
给?赋值:
* 方法: setXxx(参数1,参数2) Xxx表明数据类型
* 参数1:?的位置编号 从1 开始
* 参数2:?的值
咱们了解了关于JDBC一些基础的实现,发现每次书写JDBC的代码时,总会有一些重复的步骤,很是的繁琐,因此为了方面咱们书写代码,能够开发一个JDBC的实现类,实现相同的效果。
一、首先咱们想要获取链接对象,可是不想经过传递参数的方法,由于这样也很麻烦,为了保证工具类的通用性,咱们使用配置文件的方式,配置一个jdbc.properties文件,里面放入一些固定的配置,之后只须要修改里面的数据库名称就好。
url = jdbc:mysql://127.0.0.1:3306/spj?&useSSL=false&serverTimezone=UTC user = root password = 123456 driver = com.mysql.cj.jdbc.Driver
二、
1 import java.io.FileReader; 2 import java.io.IOException; 3 import java.net.URL; 4 import java.sql.*; 5 import java.util.Properties; 6 7 /* 8 JDBC工具类 9 */ 10 public class Demo01JdbcUtils { 11 private static String url; 12 private static String password; 13 private static String user; 14 private static String driver; 15 16 /** 17 * 文件的读取,只须要读取一次便可拿到这些值,使用静态代码块。 18 */ 19 static { 20 try { 21 Properties pro=new Properties(); 22 //获取src路径下的文件方式: 使用ClassLoader 类加载器 23 24 ClassLoader classLoader = Demo01JdbcUtils.class.getClassLoader(); 25 URL res = classLoader.getResource("jdbc.properties"); 26 String path=res.getPath(); 27 System.out.println(path); 28 29 30 pro.load(new FileReader(path)); 31 url=pro.getProperty("url"); 32 user=pro.getProperty("user"); 33 password=pro.getProperty("password"); 34 driver=pro.getProperty("driver"); 35 36 Class.forName(driver); 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } catch (ClassNotFoundException e) { 40 e.printStackTrace(); 41 } 42 } 43 44 /** 45 * 获取链接 46 * @return 链接对象 47 */ 48 public static Connection getConnection() throws SQLException { 49 return DriverManager.getConnection(url,user,password); 50 } 51 52 /** 53 * 释放资源 54 * @param stat 55 * @param conn 56 */ 57 public static void close(Statement stat,Connection conn) 58 { 59 if (stat != null) { 60 try { 61 stat.close(); 62 } catch (SQLException e) { 63 e.printStackTrace(); 64 } 65 } 66 if (conn != null) { 67 try { 68 conn.close(); 69 } catch (SQLException e) { 70 e.printStackTrace(); 71 } 72 } 73 } 74 public static void close(ResultSet rs,Statement stat,Connection conn) 75 { 76 if (stat != null) { 77 try { 78 stat.close(); 79 } catch (SQLException e) { 80 e.printStackTrace(); 81 } 82 } 83 if (conn != null) { 84 try { 85 conn.close(); 86 } catch (SQLException e) { 87 e.printStackTrace(); 88 } 89 } 90 if (rs != null) { 91 try { 92 rs.close(); 93 } catch (SQLException e) { 94 e.printStackTrace(); 95 } 96 } 97 } 98 99 }
1. 事务是做为单个逻辑工做单元执行的一系列操做。
2. 一个逻辑工做单元必须有四个属性,称为原子性、一致性、隔离性和持久性 (ACID) 属性,只有这样才能成为一个事务(要么同时成功,要么同时失败)
Connection类中提供了3个事务处理方法:
• setAutoCommit(Boolean autoCommit):设置是否自动提交事务,默认为自动提交,即为true,经过设置false禁止自动提交事务,在执行sql以前使用此方法;
• commit():提交事务,当全部sql都执行完提交事务;
• rollback():回滚事务,在catch中回滚事务.
1 public static void main(String[] args) { 2 Connection conn = null; 3 4 PreparedStatement stmt1 = null; 5 PreparedStatement stmt2 = null; 6 ResultSet rs = null; 7 try { 8 conn= Demo01JdbcUtils.getConnection(); 9 //开启事务 10 conn.setAutoCommit(false); 11 12 String sql1="update s set STATUS = STATUS -? where sno=?"; 13 String sql2="update s set STATUS = STATUS +? where sno=?"; 14 stmt1=conn.prepareStatement(sql1); 15 stmt2=conn.prepareStatement(sql2); 16 stmt1.setInt(1,20); 17 stmt1.setString(2,"s1"); 18 stmt2.setInt(1,30); 19 stmt2.setString(2,"s2"); 20 stmt1.executeUpdate(); 21 //手动制造异常 22 int i=3/0; 23 stmt2.executeUpdate(); 24 25 conn.commit(); 26 27 } catch (Exception e) { 28 try { 29 if(conn!=null) 30 conn.rollback(); 31 } catch (SQLException throwables) { 32 throwables.printStackTrace(); 33 } 34 e.printStackTrace(); 35 }finally { 36 Demo01JdbcUtils.close(stmt1,conn); 37 Demo01JdbcUtils.close(stmt2,null); 38 } 39 }
数据库定义了4个隔离级别:
分别对应Connection类中的4个常量
其实就是一个容器(集合),存放数据库链接的容器。
当系统初始化好后,容器被建立,容器中会申请一些链接对象,当用户来访问数据库时,从容器中获取链接对象,用户访问完以后,会将链接对象归还给容器。
与大二这学期学习的操做系统中线程池有着差很少的含义。
• 数据库的链接的创建和关闭是很是消耗资源的
• 频繁地打开、关闭链接形成系统性能低下
一、首先须要导入相应的jar包
二、定义配置文件:
* 名称: c3p0.properties 或者 c3p0-config.xml
* 路径:直接将文件放在根目录下便可。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <c3p0-config> 3 <!-- 默认链接池--> 4 <default-config> 5 <property name="driverClass">com.mysql.cj.jdbc.Driver</property> 6 <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/spj?useSSL=true&characterEncoding=utf8&serverTimezone=UTC</property> 7 <property name="user">root</property> 8 <property name="password">123456</property> 9 <property name="initialPoolSize">5</property> 10 <property name="maxPoolSize">20</property> 11 </default-config> 12 /* 13 默认链接池最大容量是20 14 */
1 public static void main(String[] args) throws SQLException { 2 3 DataSource ds=new ComboPooledDataSource();//使用默认配置 4 5 for(int i=1;i<=21;i++) 6 { 7 Connection coon=ds.getConnection(); 8 System.out.println(i+":"+coon); 9 //第五个使用完归还链接池 10 if(i==5) 11 coon.close(); 12 } 13 } 14
数据库链接池实现技术,由阿里巴巴提供的
步骤:
定义配置文件:
* 是properties形式的
* 能够叫任意名称,能够放在任意目录下
driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/spj?&useSSL=false&serverTimezone=UTC username=root password=123456 initialSize=5 maxActive=10 maxWait=3000
1 public static void main(String[] args) throws Exception { 2 3 //加载配置文件 4 Properties pro=new Properties(); 5 InputStream resourceAsStream = Demo01Druid.class.getClassLoader().getResourceAsStream("druid.properties"); 6 pro.load(resourceAsStream); 7 //获取链接池对象 8 DataSource ds = DruidDataSourceFactory.createDataSource(pro); 9 //获取链接 10 Connection conn=ds.getConnection(); 11 System.out.println(conn); 12 13 }
1 import Demo02Druid.Demo01Druid; 2 2 import com.alibaba.druid.pool.DruidDataSourceFactory; 3 3 4 4 import javax.sql.DataSource; 5 5 import java.io.IOException; 6 6 import java.io.InputStream; 7 7 import java.sql.Connection; 8 8 import java.sql.ResultSet; 9 9 import java.sql.SQLException; 10 10 import java.sql.Statement; 11 11 import java.util.Properties; 12 12 13 13 /* 14 14 Druid链接池的工具类 15 15 16 16 */ 17 17 public class JDBCUtils { 18 18 //一、定义成员变量 19 19 private static DataSource ds; 20 20 static { 21 21 22 22 try { 23 23 //加载配置文件 24 24 Properties pro=new Properties(); 25 25 InputStream resourceAsStream = Demo01Druid.class.getClassLoader().getResourceAsStream("druid.properties"); 26 26 pro.load(resourceAsStream); 27 27 //获取链接池对象 28 28 ds = DruidDataSourceFactory.createDataSource(pro); 29 29 30 30 } catch (IOException e) { 31 31 e.printStackTrace(); 32 32 } catch (Exception e) { 33 33 e.printStackTrace(); 34 34 } 35 35 } 36 36 /** 37 37 * 获取链接 38 38 */ 39 39 public static Connection geConnection() throws SQLException { 40 40 return ds.getConnection(); 41 41 } 42 42 /** 43 43 * 释放资源 44 44 */ 45 45 public static void close(Statement stat,Connection conn) 46 46 { 47 47 if (stat != null) { 48 48 try { 49 49 stat.close(); 50 50 } catch (SQLException e) { 51 51 e.printStackTrace(); 52 52 } 53 53 } 54 54 if (conn != null) { 55 55 try { 56 56 conn.close(); 57 57 } catch (SQLException e) { 58 58 e.printStackTrace(); 59 59 } 60 60 } 61 61 } 62 62 public static void close(ResultSet rs, Statement stat, Connection conn) 63 63 { 64 64 if (stat != null) { 65 65 try { 66 66 stat.close(); 67 67 } catch (SQLException e) { 68 68 e.printStackTrace(); 69 69 } 70 70 } 71 71 if (conn != null) { 72 72 try { 73 73 conn.close(); 74 74 } catch (SQLException e) { 75 75 e.printStackTrace(); 76 76 } 77 77 } 78 78 if (rs != null) { 79 79 try { 80 80 rs.close(); 81 81 } catch (SQLException e) { 82 82 e.printStackTrace(); 83 83 } 84 84 } 85 85 } 86 86 /** 87 87 * 获取链接池方法 88 88 */ 89 89 public static DataSource getDataSource() 90 90 { 91 91 return ds; 92 92 }
Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发
* 步骤:
JdbcTemplate template = new JdbcTemplate(ds);
* update():执行DML语句。增、删、改语句
* queryForMap():查询结果将结果集封装为map集合,将列名做为key,将值做为value 将这条记录封装为一个map集合
* 注意:这个方法查询的结果集长度只能是1
* queryForList():查询结果将结果集封装为list集合
* 注意:将每一条记录封装为一个Map集合,再将Map集合装载到 List集合中
*query():查询结果,将结果封装为JavaBean对象
query的参数:RowMapper
* 通常咱们使用BeanPropertyRowMapper实现类。能够完成数据到 JavaBean的自动封装
*new BeanPropertyRowMapper<类型>(类型.class)
* queryForObject:查询结果,将结果封装为对象
* 通常用于聚合函数的查询