一、三个部分
1.获取连接
jdbc:mysql:///abc 等同于 jdbc:mysql://localhost:3306/abc
指的是数据库名称也就是说第三个'/'代表 'localhost:3306/'
2.处理或者预处理语句
参数:
String name = "'or 1 or'";
拼接sql语句.
String sql = "select * from user where name = '"+name+"'";
底层的语句":
select * from user where name = '' or 1 or '';
解决:
使用PrepareStatement代替Statement
ps = conn.prepareStatenebt(sql)
3.执行查询或者更改
二、整体流程与代码示例及优化过程
从前到后的优化
一开始所有的都在操作类中,创建连接,关闭什么的,具体操作逻辑。
然后抽取出来创建链接,关闭连接放在JdbcUtils里面完成
然后考虑到效率问题,有了数据源[内部封装了一个connection连接池]。相当于数据库与代码的中间对象。所以封装了一个自己的Connection,重写了close方法[放回连接池]。[方法太多,代理模式,反射动态代理]
然后考虑到增删改查代码冗余,抽象为一个AbstractDao抽象类。[模板设计模式,策略设计模式]
核心代码及对象
-
两操作(两种返回值)
-
三对象
-
单例模式工具类
-
两操作
- 查询
- 增删改
static void query() throws SQLException {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
sql = null;
try {
sql = "";
conn = JDBCUtils.getConnection();
// st = conn.createStatement();
ps = conn.prepareStatement();
rs = st.executeQuery("");
while (rs.next()){
System.out.println(rs.getObject(1)+" "
+rs.getObject("id")); // 建议用列名
}
}finally {
JDBCUtils.free(rs,st,conn);
}
}
static int update() throws SQLException {
// 增删改都是update 返回的是一个int 类型,不需要对结果集做处理
Connection conn = null;
Statement st = null;
ResultSet rs = null;
String sql;
int i;
try {
sql = "";
conn = JDBCUtils.getConnection();
st = conn.createStatement();
i = st.executeUpdate(sql);
// 数据库客户端里面修改的话 就会 显示有多少条受影响 这个同理
}finally {
JDBCUtils.free(rs,st,conn);
}
return i;
}
- 工具类
public final class JDBCUtils {
private static String url = "jdbc:mysql://localhost:3306/jdbc";
private static String user = "root";
private static String password = "root";
static {
try {
Class.forName("com.mysql.jdbc.Driver"); // 保证注册驱动只会做一次
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError(e);
}
}
private JDBCUtils(){} // 私有的构造方法保证不能被创建
public static Connection getConnection(){
try {
return DriverManager.getConnection(url,user,password);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void free(ResultSet rs,Statement st,Connection conn){
try {
if (rs != null){
rs.close(); // 如果这一行抛异常 也会进行
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if(st != null){
st.close();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
}
单例模式 https://www.jianshu.com/p/3bfd916f2bb2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4T3CgL3x-1584434044950)(https://note.youdao.com/yws/res/17336/720E32DB04DB4BF88953905DB6AB79EE)]
注意点
-
rs.getObject(1) // 是数据库语句中列的索引号,也可以写成string字段
-
ps.setString(1,name);
-
connection关掉后通过connection创建的rs、st都无效了
异常处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CwoNzlf7-1584434044955)(https://note.youdao.com/yws/res/17525/D008973A2188410A87E91FE94E1FC5BD)]
- 把异常转化为运行时异常(一定不能catch住什么都不做)
Java 从一开始就内置了异常处理,因此你不得不使用它。这是 Java 语言唯一接受的错误报告方法。
如果没有编写适当的异常处理代码,你将会收到一条编译时错误消息。这种有保障的一致性有时会让程序的错误处理变得更容易。
抽象基本类
public abstract class AbstractDao {
public int update(String sql,Object[] obj){
try (
Connection connection = DataSourcePool.getConnection();
PreparedStatement preparedStatement =
connection.prepareStatement(sql);
ResultSet resultSet = null;
// 这一点还是传统写法比较好, 不用传统的注意也行只要重写close方法,不迷就行
// 因为Connection关闭的方法都变了,重写aotuclose接口的方法
){
int a = 0;
for(Object i : obj){
preparedStatement.setObject(++a,obj);
}
return preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException();
}
/**
* 实体dao继承abstract
*
* public int update(User user){
* String sql = "update user set name=?,birthday=? where id=?";
* Object[] args = new Object[]{
* user.getName(),user.getBirthday(),user.getId()
* };
* super.update(sql,args);
* }
* */
}
public Object find(String sql,Object[] objArr){
try (
Connection connection = DataSourcePool.getConnection();
PreparedStatement preparedStatement =
connection.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery();
// 这一点还是传统写法比较好, 不用传统的注意也行只要重写close方法,不迷就行
// 因为Connection关闭的方法都变了,重写aotuclose接口的方法
){
int a = 0;
for(Object i : objArr){
preparedStatement.setObject(++a,objArr);
}
Object object = null;
while (resultSet.next()){
object = mapperRow(resultSet);
} // 这点的逻辑 因为要根据查询结果拼成一个对象 但是父类不知道对象的样子
// 交给子类处理 处理好返回就行 子类需要实现此抽象方法
return object;
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException();
}
/**
* public Object mapperRow(ResultSet resultSet){
* User user = new User();
* user.setId(1,resultSet.getInt("Id"));
* return user;
* };
* public Object find(){
* String sql = "select * from user where id=?";
* Object[] args = new Object[]{
* user.getId()
* };
* Object user = super.find(sql,args);
* return (User)user;
* }
* */
}
public abstract Object mapperRow(ResultSet resultSet);