Javaweb入门 JDBC第一天
jdbc的定义和作用
dbc(java database connectivity) java数据库连接, 其实就是利用java语言/程序连接并访问数据库的一门技术。
之前我们可以通过cmd或者navicat等工具连接并访问数据库,但是在企业开发中,我们更多的是通过程序连接并访问数据库。如果通过java程序访问数据库,就必须要使用jdbc这门技术!!
jdbc访问数据库操作
创建一个 jt_db 数据库,在库中创建一个account表,并插入三条记录,然后利用java程序查询出account表中所有的记录,并打印在控制台上。
快速人门程序了解:
创建java类并实现jdbc程序(大致分为六个步骤)
package com.tedu; import java.sql.connection; import java.sql.drivermanager; import java.sql.resultset; import java.sql.statement; //jdbc快速入门程序 public class jdbcdemo1 { public static void main(string[] args) throws exception { /* * 通过java程序查询jt_db.account表中的所有记录 * 将查询的结果输出到控制台上 */ // 1.注册数据库 class.forname("com.mysql.jdbc.driver"); // 2.获取数据库连接 connection conn = drivermanager.getconnection( "jdbc:mysql://localhost:3306/jt_db", "root", "root"); // 3.获取传输器 statement stat = conn.createstatement(); // 4.发送sql语句到数据库执行,并返回执行结果 string sql="select * from account"; resultset r = stat.executequery(sql); // 5.处理结果 // r.next();判断是否指向记录,最开始指向表头的,用一次指向下一行记录,有记录返回true while (r.next()) {//进去循环,指向第一行数据,获取数据 int id=r.getint("id"); string name=r.getstring("name"); double money=r.getdouble("money"); system.out.println(id+", "+name+", "+money); } // 6.释放资源 r.close(); stat.close(); conn.close(); } }
jdbc快速入门细节
1.注册数据驱动
//注册数据库驱动 class.forname("com.mysql.jdbc.driver");
上面这行代码是根据传入的类的全路径(包名+类名)加载一个类到内存中。
在driver类中有一个静态代码块,静态代码块中包含着注册驱动的代码。
因此上面这行代码本身其实并不能注册驱动,但是可以让注册驱动的代码执行!
2.获取数据库连接
//获取数据库连接块 connection conn = drivermanager.getconnection( "jdbc:mysql://localhost:3306/jt_db", "root", "root");
后面传入的两个参数分别是连接数据库的用户名和密码,这里不再过多描述
第一个参数是连接数据库的url地址(描述连接的是哪一个位置的哪一个库)。其中url地址的结构如下:
jdbc:mysql://localhost:3306/jt_db
———— —————— -----------
协议名 主机名+端口 数据库的名字
其结构类似于平时访问的网址:
http://www.baidu.com:80/index.html?user=zhangfei
另外在url后面可以通过问号拼接参数:
jdbc:mysql:///jt_db?characterencoding=utf-8
characterencoding=utf-8 可以预防jdbc乱码
(可以避免通过jdbc往数据库插入中文数据时乱码
同时也可以避免通过jdbc从数据库查询数据时出现中文乱码问题)
3.statement传输器对象
stat.executequery( sql ) – 执行查询类的sql语句, 执行的结果是一个resultset对象, 其中包含了查询的结果
stat.executeupdate( sql ) – 执行增删改类型的sql语句, 执行的结果是一个int值, 表示影响的记录行数。
4.resultset结果集对象
resultset结果集其中包含了sql查询后的结果, 该对象上提供了遍历数据的方法和获取数据的方法:
(1)遍历数据行的方法
rs.next() – 将指向数据行的箭头往下挪动一行, 如果挪动一行后指向了一行记录, 方法将返回true, 否则返回false。
(2)获取数据的方法
rs.getint( colname )
rs.getstring( colname )
rs.getdouble( colname )
rs.getobject( colname )
...
5.释放资源
rs.close();
stat.close();
conn.close();
释放时遵循一个顺序, 越晚获取的越先关闭!!
jdbc增删改查
1、新增:往account表中插入一条新的记录,name为 "john",money为3000
@test public void add() throws exception{ /* * 新增:往account表中插入一条新纪录,name为"join",money为30000 */ class.forname("com.mysql.jdbc.driver"); connection conn = drivermanager.getconnection( "jdbc:mysql://localhost:3306/jt_db", "root", "root"); statement stat = conn.createstatement(); string sql="insert into account values (null,'john',3000)"; int r = stat.executeupdate(sql);//返回影响的行数 system.out.println("影响的行数:"+r); stat.close(); conn.close(); }
2、修改:修改account表中name为 "john" 的记录,将金额改为1500
@test public void update() throws exception{ /* * 修改account表中name为 "john" 的记录,将金额改为1500 */ connection conn = jdbcutil.getconn(); statement stat = conn.createstatement(); string sql="update account set money =1500 where name='john' "; int r = stat.executeupdate(sql); system.out.println("影响行数:"+r); jdbcutil.close(conn, stat, null); }
3、删除:删除account表中name为 "john" 的记录
@test public void delete() throws exception{ /* * 删除:删除account表中name为 "john" 的记录 */ connection conn = jdbcutil.getconn(); statement stat = conn.createstatement(); string sql="delete from account where name='john'"; int r = stat.executeupdate(sql); system.out.println("影响行数:"+r); jdbcutil.close(conn, stat, null); }
4、查询:查询account表中id为1的记录
@test public void find() throws exception{ /* * 查询account表中id为1的记录 */ connection conn = jdbcutil.getconn(); statement stat = conn.createstatement(); string sql="select * from account where id=1"; resultset r = stat.executequery(sql); // while (r.next()) { // int id=r.getint("id"); // string name=r.getstring("name"); // double money=r.getdouble("money"); // system.out.println(id+","+name+","+money); // } if(r.next()){ int id=r.getint("id"); string name=r.getstring("name"); double money=r.getdouble("money"); system.out.println(id+","+name+","+money); } jdbcutil.close(conn, stat, r); }
上面代码中调用了工具类中注册,连接数据库和释放资源的方法
package com.tedu.util; import java.sql.connection; import java.sql.drivermanager; import java.sql.resultset; import java.sql.sqlexception; import java.sql.statement; /** jdbc工具类 */ public class jdbcutil { /** * 获取数据库连接对象并返回 * @return connection对象 * @throws exception */ public static connection getconn() throws exception{ //1.注册驱动 class.forname( "com.mysql.jdbc.driver" ); //2.获取连接 connection conn = drivermanager.getconnection( "jdbc:mysql:///jt_db?characterencoding=utf-8", "root", "root"); return conn; } /** * 释放jdbc程序中的资源 * @param conn 连接对象 * @param stat 传输器对象 * @param rs 结果集对象 */ public static void close(connection conn, statement stat, resultset rs){ if(rs != null){ try { rs.close(); } catch (sqlexception e) { e.printstacktrace(); } finally{ rs = null; } } if(stat != null){ try { stat.close(); } catch (sqlexception e) { e.printstacktrace(); } finally{ stat = null; } } if(conn != null){ try { conn.close(); } catch (sqlexception e) { e.printstacktrace(); } finally{ conn = null; } } } }
模拟用户登录案例
创建loginuser类,提供mian方法和login方法
public static void main(string[] args) { /* 提示用户在控制台输入用户名和密码,并接收用户名和密码 * 根据用户名和密码查询user表, 如果查询到记录, 则证明 * 用户名密码正确, 模拟登录, 否则提示用户名密码错误!!*/ scanner in = new scanner( system.in ); //1.提示用户输入用户名和密码,并接收 system.out.println("请登录..."); system.out.println("请输入用户名:"); string user = in.nextline(); system.out.println("请输入密码:"); string pwd = in.nextline(); //2.调用login方法, 传入用户名和密码进行登录操作 login( user, pwd ); } /** * 根据用户名和密码进行登录 * @param user 用户名 * @param pwd 密码 */ private static void login(string user, string pwd) { connection conn = null; statement stat = null; resultset rs = null; try { //1.注册驱动并获取连接 conn = jdbcutil.getconn(); //2.获取传输器并执行sql语句 stat = conn.createstatement(); string sql = "select * from user where username='" +user+"' and password='"+pwd+"'"; system.out.println( sql ); rs = stat.executequery( sql ); //3.处理结果 if( rs.next() ) {//用户名密码正确 system.out.println("恭喜您登录成功!!"); }else { system.out.println("登录失败! 用户名或密码不正确!!"); } } catch (exception e) { e.printstacktrace(); } }
执行时输入:
请登录... 请输入用户名: 张飞'#' 请输入密码: select * from user where username='张飞'#'' and password='' 恭喜您登录成功!!
或输入:
请登录... 请输入用户名: 张飞' or '1=1 请输入密码: select * from user where username='张飞' or '1=1' and password='' 恭喜您登录成功!!
或输入:
请登录... 请输入用户名: 请输入密码: ' or '2=2 select * from user where username='' and password='' or '1=1' 恭喜您登录成功!!
以上在用户名或密码错误的情况下也能登录,就是sql注入攻击
sql注入攻击是一种常见的网络攻击方式,其产生的原因是:
由于后台的sql语句是拼接而来的, 其中的参数是用户提交过来的, 如果用户在提交参数时, 在参数中添加了一些sql关键字或者特殊符号, 就可能会导致sql语句语义的改变,从而导致一些意外的操作,比如用户名或密码错误也能登录成功!
解决方案:
(1)通过正则对用户提交的用户名或密码进行检查, 如果其中包含
sql关键字或者特殊符号, 则提示用户名或密码输入不合法
(2)通过preparedstatement对象可以防止sql注入攻击!
防止sql注入攻击
preparedstatement对象是如何防止sql注入攻击的?
先将sql语句的骨架(包含问号占位符)发送给服务器, 让服务器编译并确定下来。
再将sql语句中的参数发送给服务器,由于前面服务器已经确定了sql语句(一旦确定就不能被改变),因此参数中即使再包含sql关键字或者特殊符号,也不会影响sql语句的语义,只会被当做普通的文本来对待!
/** * 根据用户名和密码进行登录 * @param user 用户名 * @param pwd 密码 */ private static void login(string user, string pwd) { connection conn = null; preparedstatement stat = null; resultset rs = null; try { //1.注册驱动并获取连接 conn = jdbcutil.getconn(); //2.获取传输器并执行sql语句 string sql = "select * from user where" + " username=? and password=?"; stat = conn.preparestatement( sql ); //设置sql参数(如果有?占位符) stat.setstring( 1 , user ); stat.setstring( 2, pwd ); //执行sql语句 rs = stat.executequery( );//不要再传sql语句! //3.处理结果 if( rs.next() ) {//用户名密码正确 system.out.println("恭喜您登录成功!!"); }else { system.out.println("登录失败! 用户名或密码不正确!!"); } } catch (exception e) { e.printstacktrace(); } finally { //4.释放资源 jdbcutil.close(conn, stat, rs); } }
上一篇: Flink 源码解析 —— 深度解析 Flink 是如何管理好内存的?
下一篇: Java线程间通信