目录
JDBC中都是接口,MySQL驱动实现接口后能连接MySQL数据库,Oracle驱动实现接口后能连接Oracle数据库。
得到连接的四步
- 需要引入包的MySQL连接器-java的。-驱动-加载驱动类:
的Class.forName(“类名”);
-指定网址,用户名,密码-使用的DriverManager类来获得连接对象所有的java.sql中。驱动程序实现类,都提供了静态块,块内部的代码就是把自己注册到DriverManager jabc4.0后不再需要Class.forName的步骤(会自动扫描文件),但仍需要写,以便版本兼容性
public Demo1 {
String driverClassName="com.mysql.jdbc.Driver";
String url="jdbc:mysql://localhost:3306";
String username="root";
String password="1234";
Class.forName(driverClassName); //加载驱动类Connection con = DriverManager。getConnection(网址,用户名,密码); }
如果引发异常,检查:1.三个参数正确正确 2.数据库服务器是否开启
增删改查增加/修改
- 通过Connection对象创建语句(语句发送器,向数据库发送SQL语句)
- 调用它的 int executeUpdate(String sql),可以发送DML,DDL(返回值是被植入的行数)
public class Demo2{
public void fun1 throws ClassNotFoundException,SQLExeption(){
String driverClassName="com.mysql.jdbc.Driver";
String url="jdbc:mysql://localhost:3306/mydb3";
String username="root";
String password="1234";
Class.forName(driverClassName);
Connection con=DriverManager.getConnection(url,username,password);
Statement stmt=con.createStatement();
String sql="INSERT INT stu VALUES('0003','ZhangSan',30,'male')";
int r=stmt.executeUpdate(sql);
System.out.println(r);
}
}
查询
- 得到Connection
- 得到Statement,发送select语句
- 对查询返回的“表格”进行解析
String driverClassName="com.mysql.jdbc.Driver";
String url="jdbc:mysql://localhost:3306/exam";
String username="root";
String password="1234";
Class.forName(driverClassName);
Connection con=DriverManager.getConnection(url,username,password);
Statement stmt=con.createStatement();
//ResultSet相当于一个光标(包含为null的一头一尾)
ResultSet rs=stmt.executeQuery("select * from exp");
while(rs.next()){
int num=rs.getInt(1);
String name=rs.getString("name");
Double salary=rs.getDouble("sal");
System.out.println(num+" "+name+" "+salary);
}
//关闭资源(倒关)
rs.close();
stmt.close();
con.close();
JDBC代码规范化
public void fun3(){
//定义引用
Connection con=null;
Statement stmt=null;
ResultSet=rs;
try{
String driverClassName="com.mysql.jdbc.Driver";
String url="jdbc:mysql://localhost:3306/exam";
String username="root";
String password="123";
Class.forName(driverClassName);
//实例化
con=DriverManager.getConnection(url,username,password);
stmt=con.createStatement();
rs=Setstmt.executeQuery("select * from emp");
//遍历rs
while(rs.next()){
System.out.println(rs.getObject(1)+" "+rs.getString("name")+" "+rs.getDouble("salary"));
}catch(Exception e){
throw new RuntimeException(e);
}finally{
if(rs!=null)rs.close;
if(stmt!=null)stmt.close;
if(con!=nulll)con.close;
}
Statement最为重要的方法是:
int executeUpdate(String sql)
:执行更新操作,即执行insert、update、delete语句,其实这个方法也可以执行create table、alter table,以及drop table等语句,但我们很少会使用JDBC来执行这些语句;ResultSet executeQuery(String sql)
:执行查询操作,执行查询操作会返回ResultSet,即结果集。boolean execute()
:用来执行增、删、改、查所有SQL语句。该方法返回的是boolean类型,表示SQL语句是否有结果集。
之后可用int getUpdateCount()
来获取insert、update、delete语句所影响的行数。
如果使用execute()方法执行的是查询语句,那么还要调用ResultSet getResultSet()
来获取select语句的查询结果。
ResultSet
滚动结果集
void beforeFirst()
:把光标放到第一行的前面,这也是光标默认的位置;
void afterLast()
:把光标放到最后一行的后面;boolean first()
:把光标放到第一行的位置上,返回值表示调控光标是否成功;
boolean last()
:把光标放到最后一行的位置上;boolean isBeforeFirst()
:当前光标位置是否在第一行前面;
boolean isAfterLast()
:当前光标位置是否在最后一行的后面;
boolean isFirst()
:当前光标位置是否在第一行上;
boolean isLast()
:当前光标位置是否在最后一行上;boolean previous()
:把光标向上挪一行;
boolean next()
:把光标向下挪一行;
boolean relative(int row)
:相对位移,当row为正数时,表示向下移动row行,为负数时表示向上移动row行;
boolean absolute(int row)
:绝对位移,把光标移动到指定的行上;(行数从1开始)
int getRow()
:返回当前光标所在行;- 获取结果集元数据
ResultSetMetaData getMetaData()
:得到元数据
int getColumnCount()
:获取指定集列数
String getColumnName(int colindex)
:获取指定列的列名
rs.last();
System.out.println(rs.getRow());//获得行数
System.out.println(rs.getMetaData().getColumnCount());//获得列数
三个特性
是否可滚动
是否敏感
是否可更新
- con.createStatement() 生成的结果集:不可滚动,不敏感,不可更新
con.createStatement(int,int)
第一个参数:
ResultSet.TYPE_FORWARD_ONLY:不滚动结果集
ResultSet.TYPE_SCROLL_INSENSITIVE:滚动结果集,但结果集数据不会再跟随数据库而变化
ResultSet.TYPE_SCROLL_SENSITIVE:滚动结果集,但结果集数据不会再跟随数据库而变化(没有数据库驱动支持它,不使用)
第二个参数:
CONCUR_READ_ONLY:结果集是只读的,不能通过修改结果集而反向影响数据库;
CONCUR_UPDATABLE:结果集是可更新的,对结果集的更新可以反向影响数据库。(不使用)- mysql中默认为可滚动,因此con.createStatement()生成的结果集可以滚动
PreparedStatement
是Statement的子接口
优点:
防SQL攻击
提高代码的可读性、可维护性
提高效率
/*
使用username和password去查询数据
*/
public boolean login(String username,String password){
String driverClassName="com.mysql.jdbc.Driver";
String url="jdbc:mysql://localhost:3306/mydb3";
String mysqlUsername="root";
String mysqlPassword="1234";
Class.forName(driverClassName);
Connection con=DriverManager.getConnection(url,mysqlUsername,mysqlPassword);
Statement stmt=con.createStatement();
String sql="select * from t_user where username='"+username+"'and password='"+password+"'";
ResultSet rs=stmt.executeQuery(sql);
return rs.next;
}
//SQL攻击
public void fun1() throws Exception{
String username="a' or 'a'='a'";
String password="a' or 'a'='a'";
System.out,println(login(username,password));
//select * from t_user where username='a' or 'a'='a' and password='a' or 'a'='a'
}
PreparedStatement用法
- 给出SQL模板:所有参数用?替代
- 调用 Connection 的
PreparedStatement(String sql)
- 调用
setXxx()
系列方法给?赋值 - 调用
executeUpdate()
或executeQuery()
/*
使用PreparedStatement
*/
public boolean login(String username,String password){
String driverClassName="com.mysql.jdbc.Driver";
String url="jdbc:mysql://localhost:3306/mydb3";
String mysqlUsername="root";
String mysqlPassword="1234";
Class.forName(driverClassName);
Connection con=DriverManager.getConnection(url,mysqlUsername,mysqlPassword);
/
String sql="select * from t_user where username=? and password=?";
PreparedStatement pstmt=con.prepareStatement(sql);
pstmt.setString(1,username);//给第一个问号赋值,值为username
pstmt.setString(2,password);//给第二个问号赋值,password
pstmt.executeQuery();
}
预处理的原理
- 服务器的工作:
校验SQL语句的语法
编译:一个与函数类似的东西
执行:调用函数 - PreparedStatement:
前提:数据库支持预处理(几乎都支持)
每个pstmt都与一个SQL模板绑定在一起,先把SQL模板给数据库,数据库先进行校验,再进行编译。执行时只传递参数即可。
若二次执行时,就不用再次校验语法,也不用再次编译,直接执行。 - MySQL的预编译功能默认是关闭的。需要通过参数打开。
JdbcUtils 小工具
public class JdbcUtils{
public static Connection getConnection() throws
IOException,ClassNotFoundException,SQLException{
InputStream in=JdbcUtils.class.getClassLoader().getResourseAsStream("dbconfig.properties")
面向接口编程
- 把 UserDao 修改为接口,原来的类名 UserDo 修改为 UserDaolmple
- 修改 UserService 中对 UserDao 的实例化,使用工厂来创建实例:
private UserDao userDao=DaoFactory.getUserDao();
- 创建 DaoFactory 并创建getUserDao方法
public class DaoFactory{
private static Properties props=null;
static{
try{
InputStream in=