-
使用PreparedStatement实现CRUD操作
CRUD:增、删、改、查
2.1操作和访问数据库
1、数据库连接被用于向数据库服务器发送命令和SQL语句,并接受数据库服务器返回的结果。其实一个数据库连接就是一个Socket连接。
2、在java.sql包中有三个接口分别定义了对数据库的调用的不同方式:
Statement:用于执行静态SQL语句并返回它所生成结果的对象。
PrepatedStatement:SQL语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。
CallableStatement:用于执行SQL存储过程
2.2 Statement操作数据库的弊端
问题1:存在拼串操作,繁琐
String sql="SELECT USER,PASSWORD FROM user_table WHERE user='"+user+"' AND password='"+password+"'";
问题2:存在SQL注入问题
SQL注入利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中并注入非法的SQL语句段或命令(eg:SELECT user,password FROM user_table Where user=’a’ OR 1=’AND password=’OR’1’=’1’),从而利用系统的SQL引擎完成恶意行为的做法。
代码演示
@Test
public void testLogin() {
Scanner sc=new Scanner(System.in);
System.out.println("请输入用户名");
String user = sc.next();
System.out.println("请输入密码");
String password=sc.next();
String sql="SELECT USER,PASSWORD FROM user_table WHERE user='"+user+"' AND password='"+password+"'";
User user1 = get(sql, User.class);
if (user1!=null){
System.out.println("登陆成功");
}else {
System.out.println("用户名不存在或者密码不存在");
}
为避免出现sql注入:只要使用PreparedStatement(从Statement扩展而来)取代Statement
2.3 PreparedStatement实现表数据的添加操作
操作数据库的方法变化
Driver代表数据库驱动:使用DriverManager创建Driver对象
Connection代表数据库连接:jdbc:mysql://localhost:3306(mysql 8.0)13306(mysql 5.0)/表名
PreparedStatement代表数据库操作:代表的预编译的SQL语句
常用方法:PreparedStatement(String sql)
PreparedStatement代码实现
添加操作
- 配置文件,系统类加载器,通过Properties获取配置文件信息
try {
//读取配置文件的4个基本信息
//系统类加载器
//file=new File("E:\\Idea-workspace\\ConnectionJava\\src\\jdbc_1.Properties");
//is=new FileInputStream(file);
is= ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc_1.properties");
properties=new Properties();
properties.load(is);
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url=properties.getProperty("url");
String dirverClass=properties.getProperty("dirverClass");
(2)加载驱动——dirverClass和获取连接
//加载驱动
Class.forName(dirverClass);
//获取连接
connection= DriverManager.getConnection(url, user, password);
System.out.println(connection);
(3)通过PreparedStatement预编译SQL语句——获得PreparedStatement的实例
//预编译SQL语句——返回PreparedStatement的实例
String sql="insert into customers(name,email,birth)values(?,?,?)";//?为占位符
ps = connection.prepareStatement(sql);
(4)填充占位符,为SQL语句赋值
//填充占位符
ps.setString(1,"艾薇儿");
ps.setString(2,"aiweier@qq.com");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date date = sdf.parse("1999-02-02");
ps.setDate(3,new Date(date.getTime()));
(5)执行SQL语句
//执行SQL语句
ps.execute();
System.out.println("插入成功");
完整代码如下
@Test
public void testInsert(){
InputStream is=null;
Properties properties=null;
Connection connection=null;
PreparedStatement ps=null;
//File file=null;
try {
//读取配置文件的4个基本信息
//系统类加载器
//file=new File("E:\\Idea-workspace\\ConnectionJava\\src\\jdbc_1.Properties");
//is=new FileInputStream(file);
is= ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc_1.properties");
properties=new Properties();
properties.load(is);
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url=properties.getProperty("url");
String dirverClass=properties.getProperty("dirverClass");
//加载驱动
Class.forName(dirverClass);
//获取连接
connection= DriverManager.getConnection(url, user, password);
System.out.println(connection);
//预编译SQL语句——返回PreparedStatement的实例
String sql="insert into customers(name,email,birth)values(?,?,?)";//?为占位符
ps = connection.prepareStatement(sql);
//填充占位符
ps.setString(1,"艾薇儿");
ps.setString(2,"aiweier@qq.com");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date date = sdf.parse("1999-02-02");
ps.setDate(3,new Date(date.getTime()));
//执行SQL语句
ps.execute();
System.out.println("插入成功");
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if (is!=null)
is.close();
}catch (Exception e){
e.printStackTrace();
}
try {
if (connection!=null)
connection.close();
}catch (Exception e){
e.printStackTrace();
}
try {
if (ps!=null)
ps.close();
}catch (Exception e){
e.printStackTrace();
}
}
对于操作数据库常用方法的封装
因为在大多数数据库连接中不能缺少对配置文件的获取、数据库的连接和数据库的资源和Statement的关闭操作,于是将他们全部封装在一个JDBCUtils中,直接使用方法调用,减少代码冗余。
- getConnection()方法,对配置文件进行获取以及数据库连接
/**
* 获取数据库连接操作
* @return Connection的对象,获得连接
*/
public static Connection getConnection() {
InputStream is = null;
File file = null;
Properties properties = null;
Connection connection=null;
try {
//读取配置文件的4个基本信息
// file = new File("jdbc_1.properties");
is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc_1.properties");
properties = new Properties();
properties.load(is);
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String dirverClass = properties.getProperty("dirverClass");
//加载驱动
Class.forName(dirverClass);
//获取连接
connection= DriverManager.getConnection(url, user, password);
System.out.println(connection);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null)
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return connection;
}
2.对连接和Statement的关闭
/**
* 关闭连接和Statement的操作
* @param connection
* @param ps
*/
public static void closeResource(Connection connection, Statement ps){
try {
if (connection!=null)
connection.close();
}catch (Exception e){
e.printStackTrace();
}
try {
if (ps!=null)
ps.close();
}catch (Exception e){
e.printStackTrace();
}
}
修改操作
/**
* 修改customer表中的一条记录
*/
@Test
public void test2(){
Connection connection = null;
PreparedStatement ps = null;
try {
//获取数据库连接
connection = JDBCutils.getConnection();
//预编译SQL语句——返回PreparedStatement的实例
String sql="update customers set name=? where id=?";
ps = connection.prepareStatement(sql);
//填充占位符
ps.setObject(1,"莫扎特");
ps.setInt(2,18);
//执行SQL语句
ps.execute();
System.out.println("修改成功");
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
//资源的关闭
JDBCutils.closeResource(connection,ps);
}
}
通过调用JDBCUtils的两个静态方法,减少了代码长度,使代码更好维护
通用增删改操作
因为增删改这三个操作的不同只有在预编译SQL语言时体现,则只需要通过形参来改变则就可以使增删改方法变的简便
(1)增删改的封装方法
/**
* 通用的增删改操作
*/
@Test
public void testUpdate(){
String sql="delete from customers where id=?";
update(sql,3,4,5);//删除id=3,4,5的三条数据
}
//sql中的占位符应该与可变形参obj的长度相同
public void update(String sql,Object ...objects) {
Connection connection = null;
PreparedStatement ps = null;
try {
//获取数据库的连接
connection = JDBCutils.getConnection();
//预编译SQL语句
ps = connection.prepareStatement(sql);
//填充占位符
for (int i = 0; i < objects.length; i++) {
ps.setObject(i+1,objects[i]);
}
//执行操作
ps.execute();
System.out.println("操作完成");
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
//关闭资源
JDBCutils.closeResource(connection,ps);
}
}
}
(2)对封装方法的测试
/**
* 通用的增删改操作
*/
@Test
public void testUpdate(){
String sql="delete from customers where id=?";
update(sql,3,4,5);//删除id=3,4,5的三条数据
}