JDBC底层应用
JDBC用于在JAVA中对SQL数据库进行操作,包括但不限于Mysql,Oracle(甲骨文),Server Sql.
这些都可以通过JDBC用统一标准进行实现,那就是导入上述Mysql环境各自的jar包.
如Mysql的Jar包’mysql-connector-java-5.1.37-bin.jar’
此篇章为底层JDBC应用,目前已经被各种Jar包所代替,因此仅做了解.
一.使用步骤
实现步骤有两种方案,
第一种是用**createStatement()方法实现,这个步骤属于老旧的SQL语法步骤,存在SQL注入漏洞,如:or ‘1’ = '1’这样的漏洞,因此createStatement()这种方法方案已经淘汰不用
第二种是prepareStatement()**方法实现,这个方案可以避免SQL注入漏洞,其中多了一个给SQL语句中的问号赋值的步骤(如果SQL语句中不存在问号,则略过此步骤,可仍用PrepareStatement方案),且执行SQL语句时,括号内不需要填写SQL语句.目前都用这个方案.
步骤1:导入Jar包
右键单击项目目录 → New → Directory → 自定义文件名为’lib’并创建 → 将’mysql-connector-java-5.1.37-bin.jar’驱动包复制到’lib’目录下 → 右键单击’bin’目录 → 选择’Add as Library’以便添加成库.
步骤2:注册驱动
以反射形式注册 格式: Class.forName(“com.mysql.jdbc.Driver”);
注意:在mysql驱动包第五版本以后,可以在java代码中省略’注册驱动’这一步骤,因为在五版本中的jar包内会自动注册驱动.但还是建议在java代码中写上.
步骤3:定义SQL连接对象
格式:Connection 自定义sql连接对象名 = DriverManager.getConnection("jdbc:mysql://数据库IP地址:端口/数据库名","用户名","用户密码");
列如:
Connection sqlObj = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","root");
注意:如果连接的是本机,则括号内的内容可以省略为:“jdbc:mysql:///数据库名”,“用户名”,“密码”
步骤4 定义SQL语句
此步骤定义SQL语句,接下来用于执行语句的方法会因为你的SQL语句类型而不同.
如:
String sqlOfDql = "SELECT * FROM student3";//用于DQL操作
此处语句是用于查询操作的DQL类型SQL语句.因此如果想要执行该语句,则需要用到对应DQL的方法.
步骤5 定义SQL执行对象
SQL执行对象是用于执行SQL语句的.
方案一(已弃用):定义老版本的执行对象
格式:Statement 自定义SQL语句执行对象名 = 自定义sql连接对象名.createStatement();
列如:
Statement sqlAp = sqlObj.createStatement();
注意:如果用该方法定义SQL执行对象,则无法防止SQL注入
方案二:定义防止注入的执行对象
格式:PreparedStatement 自定义SQL语句执行对象名 = 自定义SQL连接对象.prepareStatement(String类型的SQL语句);
列如:
PreparedStatement sqlGo = sqlObj.prepareStatement(sqlOfstr);
步骤6/执行SQL 方案一(弃用)
方式1
任何语句类型的SQL语句(不推荐)
得到一个Boolean结果,代表是否执行成功
格式:boolean 自定义结果接收名 自定义SQL语句执行对象名.execute(String类型的SQL语句);
方式2
DDL/DML的SQL语句(可用SQLyog代替)
执行后得到一个数值,该代表了几行sql数据受到影响
格式:int 自定义影响行数接收名 = 自定义SQL语句执行对象名executeUpdate(String类型的SQL语句);
方式3
DQL的SQL查询语句
返回一个RsultSet集合,用于容纳所查询出的结果
格式:ResultSet 自定义接收结果集合名 自定义SQL语句执行对象名.executeQuery(String类型的查询语句);
步骤6/执行SQL 方案二
参数赋值
如果SQL语句中存在问号,意味着这个语句需要通过PrepareStatement的setString()方法来指定问号中的参数,以达到防止SQL注入的目的.
假如SQL语句中不存在问号,则可直接略过此’参数赋值’步骤.
格式:自定义SQL语句执行对象名.setString(问号所在编号,需要给问号赋值的String类型之参数 );
列如:
sqlGo.setString(1,user );
方式1
任何语句类型的SQL语句(不推荐) 返回一个boolean值,true为执行成功,flase为失败
格式:boolean 自定义结果接收名 自定义SQL语句执行对象名.execute();
方式2
DDL/DML的SQL语句(推荐用SQLyog代替) 返回一个值,代表了成功执行的行数
格式:int 自定义影响行数接收名 = 自定义SQL语句执行对象名executeUpdate();
方式3
DQL的SQL查询语句 返回一个ResultSet集合,存储了所查询出来的数据.
格式:ResultSet 自定义接收结果集合名 自定义SQL语句执行对象名.executeQuery();
列如:
ResultSet resultSet = sqlGo.executeQuery();
步骤6.2获取ResultSet内容
当你使用方式三进行SQL查询语句后,结果会返回到一个ResultSet集合里头,此时有多个方法可以用.
以下列出常用的
方法1:判断集合是否有数据
格式:自定义接收结果集合名.next();
列如:
if (resultSet.next()){
System.out.println("登陆成功!");
}else {
System.out.println("登陆失败!用户名或密码错误");
}
方法2:获取集合内容
依照某列的数据类型来获取相应列的数据
方法的参数内容可以用int数字表达列所在的位置,也用String字符串直接锁定列名
格式:列的数据类型 变量名 = 自定义接收结果集合名.getXXX(用int数字表达列所在的位置/用String字符串直接锁定列名);
列如:
int idParam= resultSet.getInt(1);//为数字'1'则表示从左往右数,获取第一列的数据.此处对应'ID'列
String nameParam = resultSet.getString(2); //为数字'2',则表示获取第二列的数据,此处对应'name'列
String addressParam = resultSet.getString("address");//用String字符串,则意味着直接锁定某个列.
步骤7 关闭资源占用
注意:应先关闭’SQL语句执行对象’的资源占用,再去关闭’SQL连接对象’的资源占用
关闭SQL执行语句对象
格式:自定义SQL语句执行对象名.close();
关闭SQL连接对象
格式:自定义SQL连接对象.close();
关闭ResultSet集合对象
格式:ResultSet集合对象名.close();
二.事务管理
事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
2. 操作:
1. 开启事务
2. 提交事务
3. 回滚事务
3. 使用Connection对象来管理事务
* 开启事务:自定义SQL连接对象.setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
* 在执行sql之前开启事务
* 提交事务:自定义SQL连接对象.commit()
* 当所有sql都执行完提交事务
* 回滚事务:自定义SQL连接对象.rollback()
* 在catch中回滚事务
创建连接与释放资源的工具类
工具类
这是一个工具类,用于注册驱动,定义SQL连接和SQL参数配置,以及处理资源释放
public class MyJdbc {
private static String url;
private static String user;
private static String password;
private static String driver;
static {
//先反射类文件以绝对路径通过IO流来加载当前类文件(MyJdbc)所在src模块目录下的文件.
InputStream InputObj = MyJdbc.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties prop = new Properties();
try {
prop.load(InputObj);
// prop.load(new FileInputStream("D:\\IdeaProjects\\senior-code\\day19-Senior-JDBC\\src\\jdbc.froperties"));
url = prop.getProperty("url");
user = prop.getProperty("user");
password = prop.getProperty("password");
driver = prop.getProperty("driver");
//注册驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
prop.clear();//释放资源
}
}
public static Connection connect() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
public static void exceptionofClose(Connection sqlObj, PreparedStatement sqlGo, ResultSet rs) {//用于释放资源的方法
if (sqlObj != null) {//处理Sql连接对象
try {
sqlObj.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (sqlGo!=null){//处理PrepareStatement的SQL语句执行对象.
try {
sqlGo.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (rs!=null){//处理ResultSet集合
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
测试调用类
public class testJdbc {
public static void main(String[] args) throws SQLException {
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名");
String userParam = sc.nextLine();
System.out.println("请输入密码");
String password = sc.nextLine();
if (userParam != null && password != null) {
loginMethod(userParam, password);
}
}
public static void loginMethod(String user, String password) {
//预备定义sql数据库对象
Connection sqlObj = null;
PreparedStatement sqlGo = null;
ResultSet rs = null;
try {
sqlObj = MyJdbc.connect();
//定义一个操作表数据的SQL语句,如增加数据
String sqlOfstr = "SELECT * FROM student3 WHERE name = ? and age = ?";//这里以判断名字是否对应到年龄来模仿帐户和密码.
//通过调用数据库对象的'prepareStatement'方法,传递sql语句参数,并返回给类型为'prepareStatement'的对象'sqlGO'
sqlGo = sqlObj.prepareStatement(sqlOfstr);
//给sql语句问号处,这样做的好处是可以防止sql注入 方法:setString(问号所处位置的索引号,要给其赋值的数据)
sqlGo.setString(1,user );
sqlGo.setString(2,password );
//接收返回结果
rs = sqlGo.executeQuery();
//通过查询功能来判断该账号是否存在
if (rs.next()) {
System.out.println("登陆成功!");
} else {
System.out.println("登陆失败!用户名或密码错误");
}
//运行释放资源的方法 --- 应用于查询Dql查询的ResultSet集合
MyJdbc.exceptionofClose(sqlObj,sqlGo , rs);
} catch (Exception e) {
e.printStackTrace();
}
}
}