JDBC基础
1, 本文的内容
jdbc使用mysql数据库大致步骤:
注册驱动-->获取连接-->使用(执行sql语句获取数据)-->关闭
根据这些过程分成了这些类:
- Driver(用于获取连接,驱动类);
- Connection(Driver获取到的连接对象类);
- Statement(执行静态SQL语句并返回其生成的结果的对象,执行sql的类),还有一些子类;
- ResultSet(结果集,用于存放查询到的多条数据);
2,获取连接(Connection)
-
方法1:直接使用Driver获取连接
Driver接口提供了获取连接的connect方法,只要传入数据库的url,账号密码即可,需要其他方法可以查看官方api文档ConnectionDriver driver = new Driver(); String url="jdbc:mysql://localhost:3306/db123?characterEncoding=UTF-8&useSSL=false"; Properties properties=new Properties(); properties.setProperty("user","root"); properties.setProperty("password","12345"); Connection connection=driver.connect(url,properties) connection.close(); -
方法2:通过DriverManger来管理驱动
DriverManager提供了很多的方法,用来管理Driver相当方便,获取连接的方法进行了多次重载
注册驱动获取连接即可
示例String cl="com.mysql.jdbc.Driver"; Class c=Class.forName(cl); DriverManager.registerDriver((com.mysql.jdbc.Driver)c.getConstructor().newInstance()); String url="jdbc:mysql://localhost:3306/db123?characterEncoding=UTF-8&useSSL=false"; String user="root"; String password="asd456"; Connection c=DriverManager.getConnction(url,user,password); -
可能会出现的问题,连接报错:
-
1,Establishing SSL connection without server s identity verification is not recommended.According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if expl
解决办法:在连接mysql的url中加上?useSSL=false或者?useUnicode=true&characterEncoding=UTF-8&useSSL=false,例如//jdbc:mysql://ip:端口/数据库?useUnicode=true&characterEncoding=UTF-8&useSSL=false
-
2,user,password,拼写错误报错:Access denied for user 'root'@'localhost' (using password: NO)
-
3,配置文件密码或者账号写错:Access denied for user 'root '@'localhost' (using password: YES)
-
4,Access denied for user 'root '@'localhost' (using password: YES) 有可能是新版本mysql带来的url改变需要添加时区导致的错误
解决办法:修改时区为serverTimezone=GMT==>serverTimezone=GMT%2B8,如果改为serverTimezone=UTC,插入时时间会变;UTC代表的是全球标准时间 ,但是我们使用的时间是北京时区也就是东八区,领先UTC八个小时。
-
3,执行语句的对象
封装了执行语句的方法,获取连接对象Connection后,通过其封装的方法获得
3.1,Statement
用于执行静态SQL语句并返回其生成的结果的对象,默认情况下,每个Statement对象只能同时打开一个ResultSet对象
statement中封装了很多方法,如果有需要可以查看官方api文档,如下是比较常用的方法
-
1,boolean execute(String sql):执行sql语句,可以是update ,create,select,delete语句,任意类型
-
2,ResultSet executeQuery(String sql):返回查找的ResultSet集合
使用流程:获取对象==>执行sql==>关闭
示例:
```
Statement statement=connection.createStatement();
statement.execute("drop table jdbctest01;");//sql语句可以是一个拼接的字符串,提高程序的灵活性
//关闭资源
statement.close();
connection.close;
```
3.2,PreparedStatement
表示预编译SQL语句的对象。SQL语句已预编译并存储在PreparedStatement对象中。 然后,可以使用此对象多次有效地执行此语句。
使用流程:传入包含占位符的sql并获取对象==>设置占位符的数据==>执行==>关闭
-
1,优点:抛弃字符串拼接,使用?作为占位符。解决statament带来的sql注入问题。减少了编译次数,效率高
-
2,获取连接后,通过连接对象获取preparestatement对象:prepareStatement(String sql):这里的sql是包含了占位符的sql语句
常用方法,其余有需要查看api文档
-
1,setString(int parameterIndex, String x):给第parameterIndex个占位符附上String类型的x值,解决注入问题
-
2,setInt(int parameterIndex, int x):给第parameterIndex个占位符附上Int类型的x值,解决注入问题*
-
3,ResultSet executeQuery():返回查找的ResultSet集合,与statement的有区别,如果要填写sql语句需要完整的sql语句,具体看示例
-
4,boolean execute():返回值提示操作成功与否,可以是update ,create,select,delete语句,任意类型,与statement的有区别,如果要填写sql语句需要完整的sql语句
-
5,int executeUpdate():返回操作的行数,在该SQL语句PreparedStatement对象,它必须是一个SQL数据操纵语言(DML)语句,比如INSERT , UPDATE或DELETE ; 或者不返回任何内容的SQL语句,例如DDL语句。
示例:
```
//执行插入语句
String insertData="insert into adminTes02 values(?,?,?);";
PreparedStatement preparedStatement=connection.prepareStatement(insertData);
preparedStatement.setInt(1,1);
preparedStatement.setString(2,"jack");
preparedStatement.setString(3,"jack123");
preparedStatement.execute();//插入第一条
preparedStatement.close();
connection.close();
```
3.3,CallableStatement
用于执行SQL存储过程的接口。 JDBC API提供存储过程SQL转义语法,允许以标准方式为所有RDBMS调用存储过程
使用流程:获取对象==>设置输入参数,注册输出参数的类型(表明占位符位置,Types.包装类型)==>通过execute方法执行该过程==>处理数据(获得返回值,获取ResltSet集合)==>关闭资源连接
常用方法
-
1,连接后获取对应存储过程对象:CallableStatement prepareCall(String sql)==说明:当存储过程有in 或 out 参数时,可以使用占位符号
-
2,execute():执行对应对象的存储过程
-
3,registerOutParameter(占位符位置,Types.数据类型):注册一个输出参数
-
5,setString(int parameterIndex, String x):给第parameterIndex个占位符附上String类型的x值
-
6,setInt(int parameterIndex, int x):给第parameterIndex个占位符附上Int类型的x值
-
7,ResultSet getResultSet():获取输出结构的ResltSet
-
8,int getInt(out占位位置):返回已经注册的返回参数值,int类型
-
9,String getString(out占位符位置):返回已经注册的返回参数值,String类型
示例:
```
//调用该过程:s_ad(in Sid int,out Sname varchar(32) )String call="call s_ad(?,? )";
CallableStatement callableStatement=connection.prepareCall(call);//1,获取对象
callableStatement.setInt(1,2);//2,设置输入参数
callableStatement.registerOutParameter(2, Types.CHAR);//3,注册输出参数的类型
callableStatement.execute();//4,执行该过程
System.out.println(callableStatement.getString(2));//5,处理理数据
//6,关闭资源
callableStatement.close();
connection.close();
```
4,结果集(ResultSet)
-
1,resultSet接口接收查询结果
- excuteQuery()方法返回一个ResultSet接口,运行类型为:com.mysql.jdbc.Jdbc42ResultSet
-
2,用一个集合存放每一行的信息,需要时取出即可
-
3,用一个集合存放每一行的信息的每一列的信息,按需取出即可
常用方法:get+数据类型(int culumnIndex):获取第几列的内容
- boolean next():指针指向下一行,如果下一行为空既表示每一内容,则返回false * boolean previour():指针指向上一行,如果为首行,返回false *
- getInt(int columnIndex [String columnString]):返回指针指向这行的特定列内容,以Int类型返回
- getString(int culumnIndex [String columnString]):返回指针指向这行的特定内容,以String类型返回,会以机器默认的转码格式将byte转为String字符串,如果有需要,需要指定转码形式,用数据库中指定列的编码类型转出才不会乱码
- getObject(int culumnIndex [String columnString]):以超类Object接收
- close():关闭此Resultset对象,必须操作
使用流程:获取对象==>判断是否有下一行(必须操作)==>获取对象
示例
```
ResultSet resultSet=statement.executeQuery("select * from jdbctest01 ;");//取出对应行的内容:next():指向下一行,起始指向行名,如果不为空就返回true
while(resultSet.next()){
System.out.print(resultSet.getString(1)+" ");
System.out.println(resultSet.getString(2));
}
resultSet.close();
statement.close();
connection.close();
```
5,批处理:addBatch()
当需要成批插入或者更新记录时,可以采用Java的批量更新机制, 这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率
statement和preparedstatement都有这个批量处理的方法,执行时一次执行批量包中所有的语句
方法说明(具体看api文档):
- addBatch():将当前语句添加到批量处理的包中
- clearBatch():清空缓存包中的sql语句
示例
```
String sql = "insert into batch value(?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < 1000; i++) {
preparedStatement.setInt(1, i);
preparedStatement.setString(2, "batch" + i);
//添加到批量处理的包中
preparedStatement.addBatch();
if (i % 1000 == 0) {
preparedStatement.execute();
//清空缓存包
preparedStatement.clearBatch();
}
}
```
6,制作工具包:jdbcUtils
-
整个获取连接的流程基本一致,封装成工具,更加方便
-
url,驱动类型,user,password:加载jdbcUtiles时,加载到内存,而且这些数据可以被获取连接的所有类共享
1,这些属性都应该是静态的
2,这些属性,应该在第一次加载类时被初始化:有一个配置类,配置类载入,然后赋值
3,应该把编译异常转换为运行异常,在运行时抛出
-
提供静态获取连接的方法,提供静态的关闭资源的方法
-
示例
private static String user; private static String password; private static String Driver; private static String url; private jdbcUtil(){} static{//初始化配置 try { Properties properties = new Properties(); properties.load(new FileInputStream("src\Util\jdbcUtil.properties")); user=properties.getProperty("user"); password=properties.getProperty("password"); Driver=properties.getProperty("Driver"); url=properties.getProperty("url"); } catch (IOException e) { throw new RuntimeException(e); } } public static Connection getConnection(){ try { Class c=Class.forName(Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } try{ return DriverManager.getConnection(url,user,password); }catch(Exception e){ throw new RuntimeException(e); } } public static void close(ResultSet resultSet, Statement statement,Connection connection) { try { if (resultSet != null) { resultSet.close(); } if (statement != null) { statement.close(); } connection.close(); }catch (SQLException e){ throw new RuntimeException(e); } }
7,事务
-
1,事务仅支持innodb存储引擎,如果表的引擎不是innodb,回滚无效
-
2,流程:
- 关闭默认自动提交,既开启事务:使用连接类setAutoCommite方法设置为false:setAutoCommite(false),设置往后的语句需要手动提交,之前的语句不受影响
- 设置回滚点:使用连接类的setSavePiont方法设置回滚点,回滚点要在事务内:SavePoint setSavePiont(String name)
- 回滚:使用连接类的rollback方法回滚到特定点:rollback(SavePoint s)
- 提交:commite();
-
Connection connection = jdbcUtil.getConnection();//只用工具获取连接 connection.setAutoCommit(false);//设置为不自动提交事务 String sql = "insert into acount values(?,?)"; PreparedStatement preparedStatement = connection.prepareStatement(sql); Savepoint s; try { //执行两条语句 preparedStatement.setString(1, "ekko"); preparedStatement.setInt(2, 1000); preparedStatement.execute(); s= connection.setSavepoint();// 设置回滚点:A preparedStatement.setString(1, "jack"); preparedStatement.setInt(2, 1000); preparedStatement.execute(); //出现一个错误 System.out.println(1/0); } catch (Exception e) { try { connection.rollback(s);//回滚 }catch (SQLException e2){ e2.printStackTrace(); } } finally { connection.commit();//提交 jdbcUtil.close(null, preparedStatement,connection );}