為什么要使用占位符“?”
看一下第5點(diǎn),大家一定注意到了,寫(xiě)sql語(yǔ)句的時(shí)候用了“?”占位符,當(dāng)然有美化代碼的因素,不用占位符就要在括號(hào)里寫(xiě)“+”來(lái)拼接參數(shù),如果要拼接的參數(shù)一多,代碼肯定不好看,可讀性不強(qiáng)。但是除了這個(gè)原因,還有另外一個(gè)重要的原因,就是避免一個(gè)安全問(wèn)題。假設(shè)我們不用占位符寫(xiě)sql語(yǔ)句,那“querySomeStudents(String name) throws Exception”方法就要這么寫(xiě):
public List
{
List
Connection connection = DBConnection.mysqlConnection;
PreparedStatement ps = connection.prepareStatement(“select * from student where studentName = ‘” + studentName + “’”);
ResultSet rs = ps.executeQuery();
Student student = null;
while (rs.next())
{
student = new Student(rs.getInt(1), rs.getString(2), rs.getInt(3), rs.getString(4));
studentList.add(student);
}
ps.close();
rs.close();
return studentList;
}
上面的main函數(shù)一樣可以獲取到兩條數(shù)據(jù),但是問(wèn)題來(lái)了,如果我這么調(diào)用呢:
public static void main(String[] args) throws Exception
{
List
studentList = StudentManager.getInstance().querySomeStudents(“‘ or ’1‘ = ’1”);
for (Student student : studentList)
System.out.println(student);
}
看下運(yùn)行結(jié)果:
studentId = 1, studentName = Betty, studentAge = 20, studentPhone = 00000000
studentId = 2, studentName = Jerry, studentAge = 18, studentPhone = 11111111
studentId = 3, studentName = Betty, studentAge = 21, studentPhone = 22222222
studentId = 4, studentName = Steve, studentAge = 27, studentPhone = 33333333
studentId = 5, studentName = James, studentAge = 22, studentPhone = 44444444
為什么?看下拼接之后的sql語(yǔ)句就知道了:
select * from student where studentName = ‘’ or ‘1’ = ‘1’‘1’=‘1’永遠(yuǎn)成立,所以前面的查詢(xún)條件是什么都沒(méi)用。這種問(wèn)題是有應(yīng)用場(chǎng)景的,不是隨便寫(xiě)一下。Java越來(lái)越多的用在Web上,既然是Web,那么查詢(xún)的時(shí)候有一種情況就是用戶(hù)輸入一個(gè)條件,后臺(tái)獲取到查詢(xún)條件,拼接sql語(yǔ)句查數(shù)據(jù)庫(kù),有經(jīng)驗(yàn)的用戶(hù)完全可以輸入一個(gè)“‘‘’ or ‘1’ = ‘1”,這樣就拿到了庫(kù)里面的所有數(shù)據(jù)了。
JDBC事物
談數(shù)據(jù)庫(kù)必然離不開(kāi)事物,事物簡(jiǎn)單說(shuō)就是“要么一起成功,要么一起失敗”。那簡(jiǎn)單往前面的StudentManager里面寫(xiě)一個(gè)插入學(xué)生信息的方法:
public void addStudent(String studentName, int studentAge, String studentPhone) throws Exception
{
Connection connection = DBConnection.mysqlConnection;
PreparedStatement ps = connection.prepareStatement(“insert into student values(null,?,?,?)”);
ps.setString(1, studentName);
ps.setInt(2, studentAge);
ps.setString(3, studentPhone);
if (ps.executeUpdate() > 0)
System.out.println(“添加學(xué)生信息成功”);
else
System.out.println(“添加學(xué)生信息失敗”);
}
public static void main(String[] args) throws Exception
{
StudentManager.getInstance().addStudent(“Betty”, 17, “55555555”);
}
運(yùn)行就不運(yùn)行了,反正最后結(jié)果是“添加學(xué)生信息成功”,數(shù)據(jù)庫(kù)里面多了一條數(shù)據(jù)。注意一下:
1、增刪改用的是executeUpdate()方法,因?yàn)樵鰟h改認(rèn)為都是對(duì)數(shù)據(jù)庫(kù)的更新
2、查詢(xún)用的是executeQuery()方法,看名字就知道了“Query”,查詢(xún)嘛
可能有人注意到一個(gè)問(wèn)題,就是Java代碼在insert后并沒(méi)有對(duì)事物進(jìn)行commit,數(shù)據(jù)就添加進(jìn)數(shù)據(jù)庫(kù)了,也能查出來(lái),這是為什么呢?因?yàn)镴DK的Connection設(shè)置了事物的自動(dòng)提交。如果在addStudent(。..)方法里面這么寫(xiě):
Connection connection = DBConnection.mysqlConnection;
connection.setAutoCommit(false);
autoCommit這個(gè)屬性原來(lái)是true,JDK自然會(huì)幫助開(kāi)發(fā)者自動(dòng)提交事物了。OK,如果要改成手動(dòng)提交事物的代碼,那么應(yīng)該這么寫(xiě)addStudent(。..)方法:
public void addStudent(String studentName, int studentAge, String studentPhone) throws Exception
{
Connection connection = DBConnection.mysqlConnection;
connection.setAutoCommit(false);
PreparedStatement ps = connection.prepareStatement(“insert into student values(null,?,?,?)”);
ps.setString(1, studentName);
ps.setInt(2, studentAge);
ps.setString(3, studentPhone);
try
{
ps.executeUpdate();
connection.commit();
}
catch (Exception e)
{
e.printStackTrace();
connection.rollback();
}
}
要記得拋異常的時(shí)候利用rollback()方法回滾掉事物。
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助。
評(píng)論