文章目录
写在前面: 我是「境里婆娑」。我还是从前那个少年,没有一丝丝改变,时间只不过是考验,种在心中信念丝毫未减,眼前这个少年,还是最初那张脸,面前再多艰险不退却。
写博客的目的就是分享给大家一起学习交流,如果您对 Java感兴趣,可以关注我,我们一起学习。
前言:为什么要写这篇文章,由于长时间都是在使用连接数据库第三方框架Mybatis等,不使用JDBC操作,导致很多基础知识都朦朦胧胧似懂非懂,今天抽空把这部分内容认真复习了下,顺便写篇文章加深印象。本文以MySql为例。
一、搭建JDBC开发环境
1、搭建工程
开发环境为Intellij IDEA,项目创建很简单:
- File -> New -> Project
- 选择java,点击 Next
- 输入项目名称及保存路径,完成创建
- 在工程src同级目录创建lib包
- 将mysql驱动包放到lib下面
具体创建过程如下所示:
项目创建完毕就可以开发,项目的整体结构如下所示:
2、连接数据库工具类JdbcConnectionUtil
因为在进行数据库的增删改查的时候都需要与数据库建立连接,所以可以在项目中将建立连接写成一个工具方法,用的时候直接调用即可:
/**
* @author shuliangzhao
* @ProjectName jdbc
* @date 2020/6/7 14:08
*/
public class JdbcConnectionUtil {
//驱动
private static String DRIVER_NAME = null;
//链接
private static String URL = null;
//用户名
private static String USER = null;
//密码
private static String PASSWORD = null;
private static Connection conn = null;
static {
Properties properties = new Properties();
InputStream in = JdbcConnectionUtil.class.getClassLoader().getResourceAsStream("db.properties");
try {
properties.load(in);
DRIVER_NAME = properties.getProperty("drivername");
URL = properties.getProperty("url");
USER = properties.getProperty("user");
PASSWORD = properties.getProperty("password");
} catch (Exception e) {
throw new RuntimeException("加载配置文件失败:{}",e);
}
}
public static Connection getConnection() {
if (conn != null) {
return conn;
}
try {
Class.forName(DRIVER_NAME);
conn = DriverManager.getConnection(URL, USER, PASSWORD);
} catch (Exception e) {
throw new RuntimeException("数据库连接异常!",e);
}
return conn;
}
public static void close(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException("数据库关闭异常!",e);
}
}
}
public static void close(Statement statement) {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
throw new RuntimeException("数据库关闭异常!",e);
}
}
}
}
3、main方法测试
写main方法测试是否能连接上数据库,可能有两种错误
1、url参数问题
Caused by: com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value '�й���ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specifc time zone value if you want to utilize time zone support.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61)
解决方法为在url地址(url=jdbc:mysql://localhost:3306/chapter01?)后面加上:
&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
2、jdbc驱动问题
Caused by: java.lang.ClassNotFoundException: com.mysql.dbc.Driver
at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
需要把jdbc驱动换成:com.mysql.cj.jdbc.Driver
二、创建Statement或PreparedStatement接口,执行SQL语句
1、使用Statement接口
Statement接口创建之后,执行SQL语句,完成对数据库的增删改查。增删改只需要传入不同的SQL就可以,不过查询稍微复杂。在Statement中使用字符串拼接的方式生成SQL语句,容易发生sql注入等危险。所以一般情况下我们具体会使用PreparedStatement这个接口。
字符串拼接方式的SQL语句是非常麻烦容易出错。
public static void testStatement() throws Exception{
Connection connection = JdbcConnectionUtil.getConnection();
Statement statement = connection.createStatement();
String sql = "insert into book(author,name) values ('三毛','撒哈拉沙漠')";
statement.execute(sql);
JdbcConnectionUtil.close(connection);
JdbcConnectionUtil.close(statement);
}
注意:写SQL语句时注意把要插入的字段都加上。
2、使用PreparedStatement接口
PreparedStatement也是执行sql语句,但与创建Statement不同的是,需要根据sql语句创建PreparedStatement。除此之外,还能够通过设置参数,指定相应的值,而不是像Statement那样只能使用字符串拼接。
public static void testPreStatement() throws Exception{
Connection connection = JdbcConnectionUtil.getConnection();
String sql = "insert into book(author,name) values (?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,"李四");
preparedStatement.setString(2,"围城");
preparedStatement.executeUpdate();
JdbcConnectionUtil.close(connection);
JdbcConnectionUtil.close(preparedStatement);
}
修改和删除只需要把sql语句替换即可,在这里就不一一写出来了。
使用PreparedStatement需要注意:
- 每次SQL语句都是一样的,java类就不会再次编译,这样能够显著提高性能
- set方法给占位符进行赋值,这里的参数索引是从1开始的。
- 还可以批量插入 preparedStatement.addBatch();
- 最主要是可以防止sql注入
PreparedStatement如何防止sql注入请看:PreparedStatement是如何防止SQL注入的?
PreparedStatement接口实现查询如下:
实体类Book
public class Book {
private int id;
private String author;
private String name;
//省略get set
}
public static void testSelect() throws Exception{
Connection connection = JdbcConnectionUtil.getConnection();
String sql = "select * from book";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet resultSet = preparedStatement.executeQuery();
List<Book> books = new ArrayList<>();
while (resultSet.next()) {
int id = resultSet.getInt("id");
String author = resultSet.getString("author");
String name = resultSet.getString("name");
Book book = new Book();
book.setId(id);
book.setAuthor(author);
book.setName(name);
books.add(book);
}
System.out.println(books.size());
JdbcConnectionUtil.close(connection);
JdbcConnectionUtil.close(preparedStatement);
}
执行查询语句,返回给集合ResultSet。 这里的resultSet的get方法括号里面可以填属性值(即为数据库字段值),还可以填该属性在数据表中的列号,从1开始编码,所以执行get方法的时候,我除可以这样写resultSet.getInt(“id”),还可以这样写 resultSet.getInt(1)。但是不推荐使用列号的这种方式,因为一段数据表中个属性值得顺序发生变化,就会导致这里出错,而使用属性名则不会出现这样的问题。
Statement和PreparedStatement的优点
PreparedStatement的优点:
-
其使用参数设置,可读性好,不易记错。在statement中使用字符串拼接,可读性和维护性比较差。
-
其具有预编译机制,性能比statement更快。
-
其能够有效防止SQL注入攻击。
Connection类中有好多有用的方法比如
- getMetaData()
这个方法可以返回DatabaseMetaData,这个类可以获得数据库的url,用户名,密码等。
到此Java基础JDBC如何连接数据库、查询等已经讲完。如果还有不明白的可以留言。
本文来源代码: https://github.com/FadeHub/jdbc
—————————————————————————————————
由于本人水平有限,难免有不足,恳请各位大佬不吝赐教!