1. JDBC
作用?
通过JDBC操作保存在数据库中的数据。
重要性
学得好,以后学数据库相关框架轻松;如果不精通,不是专业的研发。
1.1. JDBC使用步骤
1.1.1. 将驱动引入项目
方式1: 新建空白工程 ,选择工程 ,右击 properties -àjava build path-àLibrary-àadd external JARS ,在弹出的选择框中选中某一个硬盘上的 连接驱动包 mysql-connector-java.-5.1.7-bin.jar
方式2:(推荐)
l 在项目根目录新建文件夹lib,把数据库驱动mysql-connector-java-5.1.7-bin.jar放入该文件夹(拷贝到该文件夹中)。
l 右键点击项目名称->properties->Java Build Path->Libraries->Add JARs->找到驱动文件->搞定
什么是mysql-connector-java-5.1.7-bin.jar?
数据库驱动。
为什么要另外引入一个jar包,sun公司怎么没有实现这些功能?
因为市面上有很多数据库,mysql oracle sqlserver,每个数据库内部实现不同,sun公司提供标准接口,数据库提供商负责实现接口,把所有实现类打包成.jar文件。有了这个jar包,java程序就可以驱动着数据库做事。
1.1.2. 测试数据库连通性
先确保java程序和数据库之间的连接正常再进行开发。
package com.njwb.connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* sqlException Access denied password use @localost yes...
* 重置root的密码
* use mysql;
* update user set password = password('root') where user = 'root';
* flush privileges;
* @author Administrator
*
*/
public class TestConn01 {
public static void main(String[] args) {
//加载驱动
try {
//固定的字符串
Class.forName("com.mysql.jdbc.Driver");
System.out.println("加载驱动成功");
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
System.out.println("加载驱动失败");
}
//获取连接对象
try {
// jdbc:mysql://ip地址:3306/数据库名 ,数据库的登录用户名 ,登录的密码
//DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/njwangbo1", "root", "root");
DriverManager.getConnection("jdbc:mysql://localhost:3306/njwangbo1", "root", "root");
System.out.println("获取连接对象成功");
} catch (SQLException e) {
e.printStackTrace();
System.out.println("获取连接对象失败");
}
}
}
1.1.3. 修改MySQL用户权限
如果连接失败,提示“is not allowed to connect to this MySQL server”,在服务器上执行:
GRANT ALL ON *.* TO root@'%' IDENTIFIED BY 'root';
GRANT ALL ON *.* TO root@'127.0.0.1' IDENTIFIED BY 'root';
允许任何IP可以使用root账户连接数据库。
1.2. 使用JDBC操作数据
1.2.1. 需求:实现用户注册功能
使用java代码在数据库中插入一条记录。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 注册新用户
* @author Administrator
*
*/
public class TestRegist {
public static void main(String[] args) {
regist("helen","123abc");
}
/**
* 根据指定的的用户名,密码注册
* @param userName
* @param pwd
*/
public static void regist(String userName,String pwd){
try {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Connection conn = null;
Statement st = null;
try {
//2.获取连接对象
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/njwangbo1", "root", "root");
//3.准备sql语句,获取sql执行器对象
String sql = "insert into t_user(t_userName,t_pwd) values('"+userName+"','"+pwd+"')";
st = conn.createStatement();
//4.执行,丙返回处理结果
int rowCount = st.executeUpdate(sql);
if(rowCount>0){
System.out.println("注册成功");
}else{
System.out.println("注册失败");
}
} catch (Exception e) {
System.out.println("conn="+conn+",st="+st);
e.printStackTrace();
}finally{
//5.关闭资源
if(null!=st){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null!=conn){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
1.2.2. 设计一张用户表
create table t_user(
t_id int auto_increment primary key,
t_userName varchar(30),
t_pwd int
)engine=InnoDB;
insert into t_user (t_userName,t_pwd)
values('tom','123456'),
('jack','123456');
1.2.3. 使用java插入数据
1.2.4. 使用完必须关闭连接
先打开的后关闭 ResultSet--> Statement/PreparedStatement--> Connection
1.2.5. 封装成增删改方法
注意:在JAVA代码中调用SQL语句,SQL末尾不需要加分号。
编写一个注册方法reg,传入两个参数用户名和密码。
在main中调用一次该方法,向数据库中写入一条记录。
编写一个方法updateById,传入两个参数用户名和id。
使用executeUpdate执行SQL语句,根据id修改用户名。
update t_user set userName = '' where id=''
在main中调用一次该方法,修改一条记录。
public static void updateById(String userName,int id)
编写一个方法delById,传入一个参数id。
使用executeUpdate执行SQL语句,根据id删除该条记录。
delete from t_user where id =
在main中调用一次该方法,修改一个用户。
public static void delById(int id);
1.2.6. 需求:实现用户登录功能
/**
* 登录的方式1:
* 根据指定的用户名, 密码 查询用户,如果能够查询到数据,则提示登录成功 ,否则登录失败
* @author Administrator
*
*/
public class TestLogin01 {
public static void main(String[] args) {
login("tom","123456");
}
/**
* 将登录封装成方法
* @param userName
* @param pwd
*/
public static void login(String userName,String pwd){
//1.加载驱动
……..
//在这边声明,方便在finally里关闭
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
//2.获取数据库连接
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/njwangbo1", "root", "root");
//3.准备sql语句,获取sql执行器对象
String sql = "select * from t_user where t_userName='"+userName+"' and t_pwd = '"+pwd+"' ";
st= conn.createStatement();
//4.执行,并返回处理结果 执行器对象st将sql语句发送到数据库,返回处理结果(返回的是ResultSet结果集对象)
rs= st.executeQuery(sql);
//判断能否查询到数据
if(rs.next()){
//System.out.println(rs.getInt("t_id")+"\t"+rs.getString("t_userName")+"\t"+rs.getString("t_pwd"));
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
//5.关闭资源
………
}
}
}
/**
* 登录的方式2:
* --根据指定的用户名,密码,查询在数据库表中出现的记录数(出现的行数),如果记录数=1,显示登录成功,否则登录失败
* @author Administrator
*
*/
public class TestLogin02 {
public static void main(String[] args) {
login("tom","123456");
}
/**
* 将登录封装成方法
* @param userName
* @param pwd
*/
public static void login(String userName,String pwd){
//1.加载驱动
……..
//在这边声明,方便在finally里关闭
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
//2.获取数据库连接
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/njwangbo1", "root", "root");
//3.准备sql语句,获取sql执行器对象
//String sql = "select count(*) from t_user where t_userName='"+userName+"' and t_pwd = '"+pwd+"' ";
String sql = "select count(*) as c from t_user where t_userName='"+userName+"' and t_pwd = '"+pwd+"' ";
st= conn.createStatement();
//4.执行,并返回处理结果 执行器对象st将sql语句发送到数据库,返回处理结果(返回的是ResultSet结果集对象)
rs= st.executeQuery(sql);
//判断能否查询到数据 (假设都不重名,只有用户名,密码正确的时候,才能返回1 )
if(rs.next() && rs.getInt("c")==1){
//System.out.println("符合条件的记录数(几行):"+rs.getInt(1));
//System.out.println("符合条件的记录数(几行):"+rs.getInt("c"));
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
//5.关闭资源
…….
}
}
}
总结
l excuteUpdate执行insert、update、delete返回影响的行数
l excuteQuery执行select返回结果集ResultSet
1.2.7. 查询用户表中所有用户
package com.njwb.connection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 查询数据库中njwangbo1的t_user表中的所有的数据,输出在console控制台中
* 1.加载驱动
* 2.获取数据库连接
* 3.准备sql语句,获取sql执行器对象(Statement PreparedStatement)
* 4.执行,并返回处理结果
* 5.关闭资源
* 注意:A. Connection 导包 java.sql.Connection ,Statement st
* B.查询 executeQuery() 返回的ResultSet 结果集对象
* 增,删,改 executeUpdate() 返回的受影响的行数 int
* C.先打开的后关闭 ResultSet--> Statement/PreparedStatement--> Connection
* @author Administrator
*
*/
public class TestQueryAll {
public static void main(String[] args) {
//1.加载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//在这边声明,方便在finally里关闭
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
//2.获取数据库连接
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/njwangbo1", "root", "root");
//3.准备sql语句,获取sql执行器对象
//String sql = "select * from t_user";
String sql = "select t_id as 'bianhao',t_userName as 'name', t_pwd as 'pwd' from t_user";
st= conn.createStatement();
//4.执行,并返回处理结果 执行器对象st将sql语句发送到数据库,返回处理结果(返回的是ResultSet结果集对象)
rs= st.executeQuery(sql);
//取出数据遍历结果集
System.out.println("用户编号\t用户名\t登录密码");
//next()判断下一个是否有值,如果有值返回true,否则返回false 作用和Iterator迭代器的hasNext()类似
while(rs.next()){
//方式1: 推荐(列名)
//System.out.println(rs.getInt("t_id")+"\t"+rs.getString("t_userName")+"\t"+rs.getString("t_pwd"));
//方式2:(索引 从1开始)
//System.out.println(rs.getInt(1)+"\t"+rs.getString(2)+"\t"+rs.getString(3));
//方式3 :(别名)
System.out.println(rs.getInt("bianhao")+"\t"+rs.getString("name")+"\t"+rs.getString("pwd"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
//5.关闭资源
if(null!=rs){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null!=st){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(null!=conn){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
1.2.8. prepareStatement
public class TestLogin012 {
public static void main(String[] args) {
//select * from t_user where t_userName='afafar23waq323' and t_pwd = ' 455gfafa' or '1' = '1'
login("afafar23waq323"," 455gfafa' or '1' = '1");
}
/**
* 将登录封装成方法
* @param userName
* @param pwd
*/
public static void login(String userName,String pwd){
//1.加载驱动
……..
//在这边声明,方便在finally里关闭
Connection conn=null;
PreparedStatement pst=null;
ResultSet rs=null;
try {
//2.获取数据库连接
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/njwangbo1", "root", "root");
//3.准备sql语句,获取sql执行器对象
String sql = "select * from t_user where t_userName= ? and t_pwd=?";
System.out.println("sql="+sql);
pst= conn.prepareStatement(sql);
//在执行之前,需要设置占位符
pst.setString(1, userName);
pst.setString(2, pwd);
//4.执行,并返回处理结果 执行器对象st将sql语句发送到数据库,返回处理结果(返回的是ResultSet结果集对象)
rs= pst.executeQuery();
//判断能否查询到数据
if(rs.next()){
System.out.println(rs.getInt("t_id")+"\t"+rs.getString("t_userName")+"\t"+rs.getString("t_pwd"));
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
//5.关闭资源
…….
}
}
}
1.2.9. Statement和prepareStatement的区别
关系: Statement是PreparedStatement的超级接口(父接口)
l statement的用法
Connection conn =DriverManager.getConnection(url,userName,pwd);
String sql = "......";
Statement st = conn.createStatement();
//增,删,改
int count = st.executeUpdate(sql);
//查询
ResultSet rs = st.execuQuery(sql);
l statement代码可读性差
insert into table1(col1,col2,col3,col4,.......) values ('+v1+"','"+v2+"','"+v3+"','"+v4+......+"')"
拼串,容易造成错误,单引号多的时候
l PrepareStatement的用法
insert into table1(col1,col2,col3,col4,.......) values (?,?,?,?)
Connection conn =DriverManager.getConnection(url,userName,pwd);
String sql = "......";
//获取执行器对象
PreparedStatement pst = conn.preparedStatement(sql);
//设置占位符
pst.setObject(1,v1);
pst.setObject(2,V2);
pst.setObject(3,V3);
pst.setObject(4,V4);
......
//执行,并返回处理结果
//增,删,改
int count = st.executeUpdate();
//查询
ResultSet rs = st.executeQuery();
l PrepareStatement代码可读性高
insert into table1(col1,col2,col3,col4,.......) values (?,?,?,?) ,占位符的方式,可读性高
l Statement拼串造成sql注入安全性问题
select * from t_user where t_userName='afafar23waq323' and t_pwd = ' 455gfafa' or '1' = '1'
如果 这样写 ,那么整张表的数据都会被删除。
select * from t_user where t_userName='afafar23waq323' and t_pwd = ' 455gfafa' or '1' = '1';drop table t_user;
l PrepareStatement预编译语句,传入任何内容不会和原来的语句发生任何匹配的关系,只要全使用预编译语句,就用不着对传入的数据做任何过虑。
/**
* sql注入 ’1‘=’1‘ 恒等,永远成立的
* 用错误的用户名,密码登陆,会将整张表的数据获取到
* @author Administrator
*
*/
public class TestLogin012 {
public static void main(String[] args) {
//select * from t_user where t_userName='afafar23waq323' and t_pwd = ' 455gfafa' or '1' = '1'
login("afafar23waq323"," 455gfafa' or '1' = '1");
}
/**
* 将登录封装成方法
* @param userName
* @param pwd
*/
public static void login(String userName,String pwd){
//1.加载驱动
…….
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
//2.获取数据库连接
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/njwangbo1", "root", "root");
//3.准备sql语句,获取sql执行器对象
String sql = "select * from t_user where t_userName='"+userName+"' and t_pwd = '"+pwd+"' ";
System.out.println("sql="+sql);
st= conn.createStatement();
//4.执行,并返回处理结果 执行器对象st将sql语句发送到数据库,返回处理结果(返回的是ResultSet结果集对象)
rs= st.executeQuery(sql);
//判断能否查询到数据
if(rs.next()){
System.out.println(rs.getInt("t_id")+"\t"+rs.getString("t_userName")+"\t"+rs.getString("t_pwd"));
System.out.println("登录成功");
sql = "drop table t_user";
int count = st.executeUpdate(sql);
//注意此处虽然显示的删除失败,count=0,但是仍旧会将数据库的整张表结构删除掉
System.out.println("#####count="+count);
if(count>0){
System.out.println("删除成功");
}else{
System.out.println("删除失败");
}
}else{
System.out.println("登录失败");
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
//5.关闭资源
}
}
}