1. JDBC
用于连接java和数据库
1.1. 连接操作步骤
-
在数据库中新建数据库和录入数据;
-
Class.forName("com.mysql.cj.jdbc.Driver");//加载驱动 DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver);//也可以用这个语句加载驱动,推荐用第一个语句,因为DriverManager源码的static类中已经存在第二个语句了,可以直接调用激活
-
String url = "jdbc:mysql://localhost:3360/jdbcstudy?useUnicod=true&characterEncoding=utf8&useSSL=true"; //通用写法:jdbc:mysql://主机地址:端口号/数据库?参数1&参数2&参数3 String username = "root"; String password = "12345678";//设置用户信息和url
-
Connection connection = DriverManager.getConneciton(url,username,password); Statement statement = connection.createStatement();//连接数据库
-
String sql = "SELECT * FROM user";//获取数据库信息并输出 ReslutSet resultset = statement.executeQuery(sql); while(resultSet.next()){ System.out.println("id=" + resultSet.getObject("id")); System.out.println("name=" + resultSet.getObject("NAME")); System.out.println("pws=" + resultSet.getObject("PASSWORD")); System.out.println("email=" + resultSet.getObject("email")); System.out.println("bir=" + resultSet.getObject("birthday")); System.out.println("====================") } resultSet.close(); statement.close(); connection.close();//记得关闭连接,不然很耗费资源 /*输出结果: id=1 name=xiaoming pwd=123 email=123@163.com bir=1998-03-04 ====================== id=2 name=xiaohong pwd=456 email=456@163.com bir=1999-05-10 ====================== id=3 name=xiaoli pwd=789 email=789@163.com bir=1997-09-26 ====================== */
1.2. JDBC对象
Statement是执行SQL的对象
String sql = ""//双引号内为要执行的SQL操作
statement.executeQuery(sql);//查询,返回ResultSet
statement.execute();//执行任何SQL
statement.executeUpdate();//更新、插入、删除都使用这条语句,返回一个受影响的行数
ResultSet获取查询的结果集
ResultSet resultSet = statement.executeQuery(sql);
resultSet.getObject();//获取全部类型结果
resultSet.getInt();//获取Int类型结果
resultSet.getString();//获取String类型结果
resultSet.getFLoat();
resultSet.getDate();
resultSet.beforeFirst();//移动到结果集最前面
resultSet.afterLast();//移动到结果集最后面
resultSet.next();//移动到下一个查询结果
resultSet.previous();//移动到上一个查询结果
resultSet.absolute(row);//移动到指定行
1.3. JDBC下的CRUD操作
-
创建数据库配置文件
driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true username=root password=123456
-
创建数据库操作接口
public class JdbcUtils{ private static String driver = null; private static String url = null; private static String username = null; private static String password = null; static{ try{ InputStream in =jdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");//输入配置信息 Properties properties = new Properties(); properties.load(in);//加载配置信息 driver = properties.getProperty("driver"); url = properties.getProperty("url"); username = properties.getProperty("username"); password = properties.gteProperty("password"); Class.forName(driver);//加载驱动 }catch(IOException | ClassNotFoundException e){ e.printStackTrace(); } } public static Connection getConnection() throws SQLException{ return DriverManager.getConnection(url,username,password);//获取数据库连接 } public static void release(Connection con,Statement sta,ResultSet res){//关闭数据库连接,避免浪费资源 if(res!=null){ try{ res.close(); }catch(SQLException e){ e.printStackTrace(); } } if(sta!=null){ try{ sta.close(); }catch(SQLException e){ e.printStackTrace(); } } if(con!=null){ try{ con.close(); }catch(SQLException e){ e.printStackTrace(); } } } }
-
调用已创建的接口
public class TestInsert{ public static void main(String[] args){ Connection con = null; Statement sta = null; ResultSet res = null; try{ con = JdbcUtils.getConnection();//创建连接 sta = con.createStatement();//创建statement String sql = "INSERT INTO user(id,`NAME`,`PASSWORD`,`email`,`birthday`)" + "VALUES(6,'lingming','888','888@163.com','1999-12-31')"; int i = sta.executeUpdate(sql);//调用statement的executeUpdate方法进行插入,插入、删除、更新都是用executeUpdate()方法,返回受影响的行数 if(i>0){ System.out.println("插入成功"); } }catch(SQLException){ e.printStackTrace(); }finally{ JdbcUtils.release(con,sta,res);//调用自己JdbcUtils类中写的关闭连接方法release } } }
删除、更新操作如上
查询操作:
String sql = "SELECT * FROM user WHERE id=1"; res sta.executeQuery(sql);//exeCuteQuery返回一个符合条件的结果集 while(res.next()){//res.next()方法表示如果还有下一行则返回true,否则返回false System.out.println(res.getString("NAME")); }//输出列属性为NAME的值
1.4. SQL注入问题
SQL注入:利用SQL语言拼接非法获取数据库信息
public class Login {
public static void main(String[] args) {
//login("stone","123");
login(" 'or '1=1"," 'or '1=1");//此情况下数据库会返回所有信息
}
public static void login(String username,String password){
Connection con = null;
Statement sta = null;
ResultSet res = null;
try {
con = JdbcUtils.getConnection();
sta = con.createStatement();
//"SELECT * FROM user WHERE `NAME`='' or '1=1'AND `PASSWORD`='' or '1=1'",这就是利用SQL语法拼接漏洞的原理,当NAME=空字符串或1=1(必定为true,即WHERE判断必定通过)时,SQL误以为输入数据符合条件继而返回数据库所有信息。
String sql = "SELECT * FROM user WHERE `NAME`='"+username+"' AND `PASSWORD`='"+ password+"'";
//参考"SELECT * FROM user WHERE `NAME`='stone' AND `PASSWORD`='123456'"
res = sta.executeQuery(sql);
while(res.next()){
System.out.println(res.getString("NAME"));
System.out.println(res.getString("PASSWORD"));
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
1.5. PreparedStatement对象
作用:防止SQL注入。
原理:将SQL语句中的条件先赋值为?号,进行预编译,之后再通过调用set类型()方法将值传入。
-
更新操作(插入、删除、更新都是调用executeUpdate()方法,这里只列举一种)
public class TestUpdate{ public static void main(String[] args){ Connection con = null; PreparedStatement sta = null; try{ con = JdbcUtils.getConnection();//获取连接 String sql = "UPDATE user SET `NAME`=? WHERE id=?";// 双引号内可替换为插入和删除语句 sta = con.prepareStatement(sql);//进行预编译 sta.setString(1,"派蒙");//对第一个属性(即NAME)进行赋值为“派蒙” sta.setInt(2,2);//对第二个属性(即id)进行赋值,值为2 int i = sta.executeUpdate();//执行更新操作,返回修改的行数 if(i>0){ System.out.println("更新成功"); } }catch(SQLException e){ e.printStackTrace(); }finally{ JdbcUtils.release(con,sta,null);//关闭连接,释放资源 } } }
-
查询操作
public class TestQuery{ public static void main(String[] args){ Connection con = null; PreparedStatement sta = null; ResultSet res = null; try{ con = JdbcUtils.getConnection(); String sql = "SELECT * FROM user WHERE id=?"; sta = con.prepareStatement(sql);//进行预编译 sta.setInt(1,2);//将id赋值为2 res = sta.executeQuery();//执行查询操作,并返回结果集 while(res.next()){ System.out.println(res.getString("NAME"));//输出结果集中属性名为NAME的值 } }catch(SQLException e){ e.printStackTrace(); }finally{ JdbcUtils.release(con,sta,res);//关闭连接,释放资源 } } }
使用preparedstatement对象后的登录操作修改为:
public static void login(String username,String password){
Connection con = null;
PreparedStatement sta = null;
ResultSet res = null;
try{
con = JdbcUtils.getConnection();
String sql = "SELECT * FROM user WHERE `NAME`=? AND `PASSWORD`=?";
sta = con.perpareStatement(sql);//进行预编译
sta.setString(1,username);//设置第一个属性NAME的值为方法的形参username
sta.setString(2,password);//设置第二个属性PASSWORD的值为方法的形参password
res = sta.executeQuery();
while(res.next()){
System.out.println(res.getString("NAEM"));
System.out.println(res.getString("PASSWORD"));
}
}
}
public class Login{
public static void main(String[] args){
login("'' or 1=1","'' or 1=1");//此时再次使用SQL注入后不会返回数据库信息,因为preparedstatement对象会自动过滤掉''字符
}
}
2. IDEA连接数据库
3. JDCB操作事务
事务的四个特点(ACID):
- 原子性:一个事务要么全部完成,要么全部不完成。
- 一致性:事务执行不能影响数据库的完整性和一致性,执行前后数据库的总数不变。
- 隔离性:两个相关联的事务之间只能串行执行,不能并行,即在同一时间不能同时运行。
- 脏读:事务A提交后又进行了撤销,导致事务B在撤销前读到的数据与数据库中的数据不一致,为脏数据,发生了脏读。
- 不可重复读:当事务A读取数据库中的数据后,事务B对数据库中该数据项进行了更新、插入或删除操作,导致事务A再次读取该数据时发现与第一个读取的数据不一致或者丢失或者多了其他数据。
- 丢失修改:事务A和事务B同时对某个数据进行修改,其中先修改的数据会被后修改的数据覆盖,导致先修改的数据丢失。
- 持久性:事务执行完后,数据库产生的变化将持久化。
Connection con = null;
con = JdbcUtils.getCOnnection();
con.setAutoCommit(flase);//关闭自动提交,打开事务
con.commit();//提交事务
con.rollback();//回滚,可以不写,默认执行失败回滚
4. DBCP,C3P0连接池
DBCP,C3P0是开源的数据库连接池,引用它们的jar包就可以直接创建数据库连接,而不需要我们自己编写连接代码。