您的位置:首页 > 编程语言 > Java开发

【JavaWeb_Part03】上位的小三之使用 JDBC 操纵 MySQL

2017-06-24 23:40 393 查看

开篇

上篇文章我们说了 MySQL 中的一些常用的命令操作,相信各位对 MySQL 的一些基本操作都已经掌握了,如果说用命令行操作 MySQL 数据库是原配的话,那么今天将的使用 Java 代码来操作数据库就是小三,为什么呢?因为在人眼里,正房永远都没有小三有吸引力,有诱惑力。

好了,言归正传,下面我们对 MySQL 来讲一些进阶的处理。如果你对命令行操作数据库还是不太熟悉的话,我推荐你先去看一下前两篇文章。电梯在下面:

1、【JavaWeb_Part01】入门 MySQL 数据库

2、【JavaWeb_Part02】与 MySQL 人鬼情未了

使用 Java 代码操作数据库

既然是使用 Java 代码操作数据库,那么还是有一定的流程。下面我们来说一下具体的操作流程。

1. 加载驱动

首先我们需要加载 MySQL 的驱动,通过如下的方式注册驱动。

Class.forName("com.mysql.jdbc.Driver");


2. 获取连接

String connectionUrl = "jdbc:mysql://localhost:3306/day01";
conn = (Connection) DriverManager.getConnection(connectionUrl, username, password); //获取数据库连接


day01 表示的是数据库名称

username 表示的是数据库的用户名

password 表示的是数据库的密码

3. 创建可执行的 SQL 语句对象

Statement createStatement();
PreparedStatement prepareStatement(String sql);
CallableStatement prepareCall(String sql);


4. 执行 SQL

int executeUpate(String sql); //执行insert update delete语句
ResultSet executeQuery(String sql); //执行select语句
boolean execute(String sql); //执行select返回true 执行其他的语句返回false


5. 释放资源

释放资源就比较简单了,通过调用 Connection 和 PrepareStatement 的 close 方法即可。

public static void release(PreparedStatement pst, Connection conn){
if(pst != null){
try {
pst.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}


6. 代码实现

上面的步骤已经说的很清楚了,下面我们只需要按部就班的按步骤来走就好了,这里就没什么可以讲的了,直接贴代码了,看不懂的直接在下面留言就好了。

1. 编写 JDBC 帮助类

JDBCHelper.java

public class JDBCHelper {
private static final String driverUrl;
private static final String connectionUrl;
private static final String username;
private static final String password;
/**
* 静态代码块,加载数据库资源
*/
static{
Properties properties = loadProperties();
driverUrl = properties.getProperty("jdbcDriver");
connectionUrl = properties.getProperty("connectionUrl");
username = properties.getProperty("username");
password = properties.getProperty("password");
}

/**
* 加载配置文件
*/
private static Properties loadProperties(){
Properties properties = new Properties();
try {
properties.load(new FileInputStream("src/db.properties"));
} catch (IOException e) {
e.printStackTrace();
}
return properties;
}

/**
* 释放链接
*/
public static void release(PreparedStatement pst, Connection conn){ if(pst != null){ try { pst.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }

/**
* 加载驱动
*/
private static void loadDriver(){
try {
Class.forName(driverUrl);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

/**
* 获取连接
*/
public static Connection getConn(){
loadDriver();
Connection conn = null;
try {
conn = (Connection) DriverManager.getConnection(connectionUrl, username, password); //获取数据库连接
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
}


2. 编写数据库信息相关配置

我这里把数据库的相关资源抽取成了配置文件,方便修改。

db.properties

jdbcDriver=com.mysql.jdbc.Driver
connectionUrl=jdbc:mysql://localhost:3306/day01
username=root
password=这里是你的数据库密码


3. 编写操纵数据库工具类

DataUtils.java

public class DataUtils {

/**
* 返回影响的行数
* @param user
* @return
*/
public static int insertUser(User user) {
int executeUpdate = 0;
PreparedStatement preparedStatement;
Connection conn = JDBCHelper.getConn();
/**
* insert into user(name, sex, age) values("xxx","x", xx);
*/
String sql = "insert into user(name, sex, age) values(?,?,?)";

try {
preparedStatement = (PreparedStatement) conn.prepareStatement(sql);
preparedStatement.setString(1, user.getName());
preparedStatement.setString(2, user.getSex());
preparedStatement.setInt(3, user.getAge());
executeUpdate = preparedStatement.executeUpdate();
JDBCHelper.release(preparedStatement, conn);
} catch (SQLException e) {
e.printStackTrace();
}
return executeUpdate;
}

/**
* 删除用户
* return 返回该操作影响的行数
*/
public static int deleteUser(String name){
PreparedStatement preparedStatement;
Connection conn = JDBCHelper.getConn();
int executeUpdate = 0;
/**
*  delect from user where name = "荆小六";
*/
String sql = "delete from user where name = '" + name +"'" ;

try {
preparedStatement = (PreparedStatement) conn.prepareStatement(sql);
executeUpdate = preparedStatement.executeUpdate();
JDBCHelper.release(preparedStatement, conn);
} catch (SQLException e) {
e.printStackTrace();
}
return executeUpdate;
}

/**
* 更新用户
*/
public static int updateUser(User user, int id){
Connection conn = JDBCHelper.getConn();
PreparedStatement preparedStatement;
int executeUpdate = 0;
/**
* update user set name = 'xxx' where id = xx;
*/
String sql = "update user set name = '" + user.getName() +"' where id = "+ id + "";
try {
preparedStatement = ((PreparedStatement) conn.prepareStatement(sql));
executeUpdate = preparedStatement.executeUpdate();
JDBCHelper.release(preparedStatement, conn);
} catch (SQLException e) {
e.printStackTrace();
}
return executeUpdate;
}

/**
* 查询所有用户
*/
public static void findAll(){
Connection conn = JDBCHelper.getConn();
/**
* select * from user;
*/
String sql = "select * from user";

PreparedStatement preparedStatement;
try {
preparedStatement = (PreparedStatement)conn.prepareStatement(sql);
ResultSet rs = preparedStatement.executeQuery();
int col = rs.getMetaData().getColumnCount();
System.out.println("user 表中的 field 字段为:" + col);
System.out.println("==================user表中的数据=====================");
while (rs.next()) {
for (int i = 1; i <= col; i++) {
System.out.print(rs.getString(i) + "\t\t");
if ((i == 2) && (rs.getString(i).length() < 8)) {
System.out.print("\t\t");
}
}
System.out.println("");
}
System.out.println("====================================================");
} catch (SQLException e) {
e.printStackTrace();
}
}


4. 编写测试类

所有的准备工作都已经准备完毕,好了,我们现在要编写我们的测试类了。

JDBCTest.java

public class JDBCTest {
//插入用户
@Test
public void testInsert(){
User user = new User();
user.setName("nvshen");
user.setSex("M");
user.setAge(23);
int i = DataUtils.insertUser(user);
System.out.println("影响行数:" + i);

}
//删除用户
@Test
public void testDelete(){
int deleteUser = DataUtils.deleteUser("荆小六");
System.out.println("影响行数:" + deleteUser);
}

//更新用户
@Test
public void testUpdate(){
User user = new User();
user.setName("孙悟空");
int updateUser = DataUtils.updateUser(user, 9);
System.out.println("影响行数:" + updateUser);
}

@Test
public void testFindAll(){
DataUtils.findAll();
}
}


执行结果:(PS:我这里只是执行了 findAll 方法,但是其他方法在截图中应该早已露出端倪,细心的小伙伴一看便知)



到这里,我们的 Java 代码操作数据库就已经完成了,不过,你以为这样就完了么?实际上并没有,如果你观察够仔细,你就会发现这些代码还是有一定的漏洞的。那么漏洞在哪里呢?当然是获取连接,你会发现,当我们每执行一次增删改查我们就通过 DriverManager.getConnection() 方法获取了一个连接,这显然是不合理的。

细节优化

上面已经抛出了彩蛋,那我下面自然就要想一些解决办法。如何能解决上面的问题呢?我们可以自定义一个连接池,连接池中默认放置 5 个连接,当我们需要链接的时候,直接去链接池中取,用完后再归还链接会链接池;如果连接池中的链接不够用了,那么我们就可以再放置 3 个连接进去。。。嗯?等等,这个东西的实现原理怎么好像见过? 没错,这就是市面上的一些链接池的套路,比如 c3p0, dbcp 等等,只不过我们现在是自己来实现,而他们封装的更好一点。这些东西,当然要知其然而知其所以然,这样才能在平时的工作中做到游刃有余。

可能有些人还不是太懂连接池,既然这样,那我就在这里科普一下连接池吧。

Connection 对象在 JDBC使用的时候,使用的时候就会去创建一个对象,使用结束以后就会将这个对象给销毁了。每次创建和销毁对象都是耗时操作,需要使用连接池对其进行优化。程序初始化的时候,初始化多个连接,将多个连接放入到池中(内存中)。每次获取的时候,都可以直接从连接池中进行获取。使用结束以后,将连接归还到池中。

好了,说干就干,我们新建一个 ArrayList 去存储连接,具体实现代码如下。

public class MyDataSource implements DataSource{
List<Connection> list = new ArrayList<Connection>();
//初始化连接池的个数
public  MyDataSource() {
for (int i = 1; i <= 5; i++) {
Connection conn = JDBCHelper.getConnection();
list.add(conn);
}
}

@Override
// 从连接池中获得连接
public Connection getConnection() throws SQLException {
if(list.size()==0){
for (int i = 1; i <= 3; i++) {
Connection conn = JDBCHelper.getConnection();
list.add(conn);
}
}
Connection conn = list.remove(0);
return conn;
}
// 归还连接
public void addBack(Connection conn){
list.add(conn);
}
}


上面的代码并不完整,但是大致思路是这样的,这就是整个自定义连接池的流程。

结语

到这里,我们使用 Java 代码操作 MySQL 数据库的操作就已经基本上完成了。大致就是这样,由于本人能力有限,写出的代码难免会有错误,如有错误,还请各位大神不吝赐教,同时也欢迎各位小朋友留言与我交流。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息