文章目录
PreparedStatement类:
定义:
PreparedStatemen是预编译声明的意思。
预编译功能:客户端发送sql语句给数据库服务器的时候,服务器有三步,编译sql-----语法分析------执行语句。
预编译的意思就是当前面执行过相似的sql语句,会把前面两步保存起来,后面执行类似的语句 可以跳过前面两步。该子接口可以让数据库开启预编译功能(前提是数据库有这个功能)。
同时,PreparedStatement是Statement的子接口,我们在以后的学习中我们可以使用PrearedStatement来代替Statement。
优点:
1 - 防止SQL攻击;
2- 提高代码的可读性,以可维护性;
3- 提高效率。
sql攻击:
通过精心构造的带有 SQL 语法的特殊输入,篡改 SQL 语句的原有结构,从而诱导数据库执行恶意代码。(这里只简单的提及一下,有兴趣的可自行百度)
使用:
先看以下代码:
String sql = “select * from tab_user where username=? and password=?”;
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setString(1, “zs”);
pstmt.setString(2, “zs”);
ResultSet rs = pstmt.executeQuery();
rs.close();
说明如下:
使用该接口的时候的sql语句是把条件用一个占位符?先放在语句里面,同时创建该语句的时候就让它与sql语句连接,后面通过SetXXX方法来给该问号的位置赋值,SetXXX里面的参数第一个数字是索引,也就是第几个问号,是从1开始的,后面就是所填的参数,最后调用调用executeUpdate()或executeQuery()方法,但要注意,调用的一定是没有参数的方法。
该接口最大的好处就是在与可以使用同一模板,我们只需要给予不同的参数来重复使用就行,另外重复使用的时候需要清空原来设置的参数,方法如下:
pstmt.clearParameters();//再次使用时需要把原来的设置的参数清空
完整使用代码展示:
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/905?useUnicode=true&characterEncoding=utf8&useSSL=false";
Connection root = DriverManager.getConnection(url, "root", "123456");
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要修改学生的学号");
int a=scanner.nextInt();
System.out.println("请输入姓名");
String name=scanner.next();
System.out.println("请输入性别");
String sex=scanner.next();
System.out.println("请输入年龄");
int ag=scanner.nextInt();
//String sql="update student set sname='"+name+"',ssex='"+sex+"',age="+ag+" where id="+a;
//Statement statement = root.createStatement();
String sql="update student set sname =?,ssex=?,age=? where id=?";
PreparedStatement ps = root.prepareStatement(sql);
ps.setString(1,name);
ps.setString(2,sex);
ps.setInt(3,ag);
ps.setInt(4,a);
int i = ps.executeUpdate();
if (i > 0) {
System.out.println("修改成功");
} else {
System.out.println("修改失败");
}
show();
ps.close();
root.close();
JDBC工具类:
背景:
学了久,我们能够发现JDBC,前面的几步都是一样的,加载类,然后创建连接,再得到PreparedStatement对象等等,并且,连接数据库一共只有四个参数,即:驱动类、url、用户名,以及密码,然而在实际开发中,我们肯定不能频繁的更改代码,而我们想要更改的话,连合以前学过的知识,我们是不是可以弄一个配置文件,通过一个工具类读取配置文件里面的参数,从而通过修改配置文件里面的参数来达到修改连接数据库的参数,
具体实现:
代码如下:
static Properties props = new Properties();
static {
InputStream in = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");
try {
props.load(in);
Class.forName(props.getProperty("driverClass"));
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
//得到连接的方法
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(props.getProperty("url"), props.getProperty("username"), props.getProperty("password"));
}
配置文件db.properties:
# 驱动类 值的后面不能敲空格
driverClass = com.mysql.jdbc.Driver
# 数据库的url
url = jdbc:mysql://localhost:3306/905?useUnicode=true&characterEncoding=utf8&useSSL=false
#用户名
username = xxxx
#密码
password = xxxxxx
另外,配置文件最好放在src目录下,因为我们是通过反射加IO流来实现对配置文件的读取,这样可以读取相对路径下的文件,而不需要绝对路径来读取。
Dao层:
概念:
数据访问层, 封装是jdbc相关的代码, 一个包
其他层的类调用Dao层的类, jdbc的相关接口不应该出现在其他层的类, 层与层的技术隔离。
规范:
-
面向接口编程
-
一个接口一个实现类
-
一个pojo类对应一个dao的接口 User --> UserDao(接口) -->UserDaoImpl(实现类)
Student -->StudentDao(接口) -->StudentDaoImpl(实现类)
-
每个dao操作对应pojo类的增删改查方法
-
每个dao的方法一般来说操作一条sql语句
eg:
事务:
适用场景:
eg: 转账:张三有10000钱,李四有10000块钱,此时张三需要转账给1000给李四。
发送sql语句:update 张三的余额为9000,update李四的余额为11000,此时可能有以下四种情况:
第一种情况: 张三减成功, 李四加成功 允许 9000 11000
第二种情况: 张三减成功, 李四加失败 不允许 9000 10000
第三种情况: 张三减失败, 李四加成功 不允许 10000 11000
第时种情况: 张三减失败, 李四加失败 允许 10000 10000
很明显,一四两种情况是双方都能接收的情况,那么我们如何把二三两种情况来变成第四种情况呢?这个时候就需要引入我们的事务这个概念了,事务是什么呢?就是把多条sql语句分成一组,在这一组sql语句里面,也就是同一个事务下,所有的语句必须全部执行成功,事务才会结束,否则会发生事务回滚,也就是会回到最初的状态,简单点来说,就是所有的sql语句都会执行失败。
事务的特性:
一共有四个,分别为原子性、一致性、隔离性、持久性。
原子性:
事务的原子性是指事务必须是一个原子的操作序列单元。事务中包含的各项操作在一次执行过程中,只允许出现两种状态之一,要么都成功,要么都失败。任何一项操作都会导致整个事务的失败,同时其它已经被执行的操作都将被撤销并回滚,只有所有的操作全部成功,整个事务才算是成功完成。
一致性:
事务的一致性是指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处以一致性状态。
比如:张三给李四转钱,不能张三扣钱了但是李四的钱没有增加。
隔离性:
事务的隔离性是指在并发环境中,并发的事务是互相隔离的,一个事务的执行不能被其它事务干扰。也就是说,不同的事务并发操作相同的数据时,每个事务都有各自完整的数据空间。一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务是不能互相干扰的
持久性:
事务的持久性是指事务一旦提交后,数据库中的数据必须被永久的保存下来。即使服务器系统崩溃或服务器宕机等故障。只要数据库重新启动,那么一定能够将其恢复到事务成功结束后的状态
相关方法:
全都是Connection下面的方法:
1-
setAutoCommit(boolean):设置是否为自动提交事务,如果true(默认值就是true)表示自动提交,也就是每条执行的SQL语句都是一个单独的事务,如果设置false,那么就相当于开启了事务了;con.setAutoCommit(false)表示开启事务!!!
2- commit():提交结束事务;con.commit();表示提交事务 3-
rollback():回滚结束事务。con.rollback();表示回滚事务
格式:
jdbc处理事务的代码格式:
try {
con.setAutoCommit(false);//开启事务…
….
…
con.commit();//try的最后提交事务
} catch() {
con.rollback();//回滚事务
}