Java连接Mysql
JDBC (Java DataBase Connection) 是通过JAVA访问数据库.
java连接mysql数据库需要第三方的类, 大多数java的类包的后缀名都是jar压缩包.
导包: Project->property->ava build path->libaries->add external jars
中文版: 项目->属性->Java构建路径->库->添加外部JAR
mysql的第三方包网上都有, 自行百度.
如果使用的mysql的包是8.0以上的版本, 那么将不适用本文的内容,具体参见菜鸟教程
初始化驱动
public class TestJDBC{
public static void main(String[] args) {
try {
//驱动类com.mysql.jdbc.Driver
//就在 mysql-connector-java-5.0.8-bin.jar中
//如果没有导入包,就会抛出ClassNotFoundException
Class.forName("com.mysql.jdbc.Driver");
System.out.println("数据库驱动加载成功 !");
}catch(ClassNotFoundException e) {
e.printStackTrace();
}
}
}
建立库连接
导入包
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
创建与数据库的Connection连接必须提供的参数有: 数据库的ip: 127.0.0.1(本机)、端口号: 3306(mysql专用端口号)、数据库名称、编码格式、账号、密码.
public static void main(String[] args) {
Connection c = null;
try {
Class.forName("com.mysql.jdbc.Driver");
c = DriverManager
.getConnection(
"jdbc:mysql://127.0.0.1:3306/test1?characterEncoding=UTF-8",
"root","mysql");
System.out.println("连接成功,连接对象: "+c);
}catch(ClassNotFoundException e) {
e.printStackTrace();
}catch(SQLException e) {
e.printStackTrace();
}finally {
if(c!=null)
try {
c.close();
}catch(SQLException e) {
e.printStackTrace();
}
}
}
}
确保mysql数据库中有test1数据库, root是用户名, mysql是密码.
连接数据库后记得关闭连接, 养成好习惯.
执行SQL语句
Statement是用于执行SQL语句的, 增删改查.
导入包
import java.sql.Statement;
保证在数据库中student1表的存在
先关闭Statement, 再关闭Connection
public static void main(String[] args) {
String name = "zhangsan";
Connection c = null;
Statement s = null;
try {
Class.forName("com.mysql.jdbc.Driver");
c = DriverManager
.getConnection(
"jdbc:mysql://127.0.0.1:3306/test1?characterEncoding=gbk",
"root","mysql");
s = c.createStatement(); //Statement是用于执行SQL语句的
// String sql1 = "insert into student1 values(null,"+"name"+","+24+","+1+")"; 使用string类型插入在数据库中无法显示
String sql = "insert into student1 values(null,"+"'guigui'"+","+24+","+1+")";
s.execute(sql);
System.out.println("执行成功");
// System.out.println("连接成功,连接对象: "+c);
}catch(ClassNotFoundException e) {
e.printStackTrace();
}catch(SQLException e) {
e.printStackTrace();
}finally { //先关闭Statement, 再关闭Connection.
if(s!=null)
try {
s.close();
System.out.println("Statement关闭成功");
}catch(SQLException e) {
e.printStackTrace();
}
if(c!=null)
try {
c.close();
System.out.println("Connection关闭成功");
}catch(SQLException e) {
e.printStackTrace();
}
}
}
}
使用try-with-resource关闭连接
把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
因为Connection和Statement都实现了AutoCloseable接口, 所有也可以使用关闭流的方式.
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try(
Connection c = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/test1?characterEncoding=gbk",
"root","mysql");
Statement s = c.createStatement();
){
String sql = "insert into student1 values(null,"+"'guigui'"+","+24+","+1+")";
s.execute(sql);
System.out.println("执行成功");
}catch(SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
在Java中的增删改查
具体过程参见上文
INSERT
SQL语句: INSERT INTO healthy VALUES(NULL, "wangliang", 81, 178.2);
String sql = "insert into healthy values(null," + "'wangliang'" + "," + 81.0f + "," + 178.2f + ")";
s.execute(sql);
使用常量和变量插入
String name = "wangliang"
int age = 24;
String sql1 = "insert into student1 values(null,"+"'"+name+"'"+","+age+","+1+")";
DELETE
SQL语句: DELETE FROM healthy WHERE name = "wangliang";
String sql = "delete from healthy where name = 'wangliang'";
//字符串要用单引号 ' '
s.execute(sql);
UPDATE
SQL语句: UPDATE healthy SET name="xiaohu" WHERE id = 3;
String sql = "update healthy set name = 'xiaohu' where id = 3";
s.execute(sql);
SELECT
select会返回数据, 所以和增删改有些不同之处
Java的中API的下标参数一般都是以0开始, 只有ResultSet和PreparedStatement的下标是从1开始.
查需要导入一个新的包
import java.sql.ResultSet;
SQL语句: SELECT * FROM healthy
String sql = "select * from healthy"
ResultSet rs = new s.executeQuery(sql);
while(rs.next()){
int id = rs.getInt("id");// 使用字段名,也可以是rs.getInt(1)
String name = rs.getString(2);// 按顺序查找
System.out.printf("%d\t%s",id,name);
}
//Statement关闭的时候,会自动关闭ResultSet
SQL语句判断账号密码
使用where匹配数据, 如果有数据返回,密码正确. 反之错.
不要select全部数据再匹配, 这样不仅效率低, 内存也吃不消.
String name = "root";
String password = "mysql";
String sql = "select * from user_table where name ='"+name+"'and password = '"+password+"'";
ResultSet rs = s.executeQuery(sql);
if(rs.next()) System.out.println("登入成功");
else System.out.println("账号密码错误");
PreparedStatement
和 Statement一样,PreparedStatement也是用来执行sql语句的
与创建Statement不同的是,需要根据sql语句创建PreparedStatement
除此之外,还能够通过设置参数,指定相应的值,而不是Statement那样使用字符串拼接.
import java.sql.PreparedStatement;
public static void main(String[] args) {
String user = "admir";
String password = "123456";
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
String sql = "insert into user_table values(null,?,?)";
try(
Connection c = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/test1?characterEncoding=gbk",
"root","mysql");
// Statement s = c.createStatement();
PreparedStatement ps = c.prepareStatement(sql);
){
ps.setString(1, user);
//ps.setString(1, "admir");
ps.setString(2, password);
ps.setString(2, "123456");
ps.execute();
}catch(SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
PreparedStatement的优点:
- 可读性好
- 预编译机制
- 防止SQL注入式攻击
PreparedStatemen使用的是参数设置, 所以可读性和维护性都比较容易; 和Statement不同, PreparedStatemen是预编译的机制, 在try中就已经预编译, 所以, 网络传输量比statement小, 数据库不需要再进行编译, 响应更快.
关于防注入攻击
如果用户提交的数据是 ‘wangliang’ OR 1=1
使用Statement进行拼接的语句将是select * from healthy where name = ‘wangliang’ OR 1=1
1=1恒成立, 那么将会把healthy表的所有数据全部查出来, 如果healthy的数据是海量的, 把几百万乃至几千万数据全部查找出来, 会让数据库负载爆, 响应变慢.
String name = "";
//中间过程省略
ps.setString(1, name); //"select * from hero where name = "'wangliang' OR 1=1""
ps.execute();
使用预编译Statement就可以杜绝SQL注入
PreparedStatement使用查询语句
execute与executeUpdate的区别
execute和executeUpdate都可以执行增加, 删除, 修改操作
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test1?characterEncoding=GBK","root", "mysql");
Statement s = c.createStatement();) {
String sqlInsert = "insert into user_table values (null,'manager',"123456")";
String sqlDelete = "delete from user_table where id = 5";
String sqlUpdate = "update user_table set password = "going" where name = "manager"";
s.execute(sqlInsert);
s.execute(sqlDelete);
s.execute(sqlUpdate);
s.executeUpdate(sqlInsert);
s.executeUpdate(sqlDelete);
s.executeUpdate(sqlUpdate);
} catch (SQLException e) {
e.printStackTrace();
}
}
executeUpdate不能执行查询操作!
execute和executeUpdate返回的类型不同
boolean isSelect = s.execute(sql);
int number = s.executeUpdate(sql);
execute的返回类型是布尔型, 返回值为true代表执行的是select的SQL语句, 返回值是false代表执行的是insert, delete, update语句.
executeUpdate的返回类型是int型, 表示有多少条数据受到了影响.
再次强调, executeUpdate不能执行select操作!
表元数据查询
元数据: 数据库服务器相关的数据, 比如版本, 引擎, 字段类型.
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public static void main(String[] args) throws Exception {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try (Connection c = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test1?characterEncoding=GBK","root", "mysql");) {
DatabaseMetaData dbmd = c.getMetaData();
// 获取数据库服务器产品名称
System.out.println("数据库产品名称:\t"+dbmd.getDatabaseProductName());
// 获取数据库服务器产品版本号
System.out.println("数据库产品版本:\t"+dbmd.getDatabaseProductVersion());
// 获取数据库服务器用作类别和表名之间的分隔符 如test.user
System.out.println("数据库和表分隔符:\t"+dbmd.getCatalogSeparator());
// 获取驱动版本
System.out.println("驱动版本:\t"+dbmd.getDriverVersion());
System.out.println("可用的数据库列表:");
// 获取数据库名称
ResultSet rs = dbmd.getCatalogs();
while (rs.next()) {
System.out.println("数据库名称:\t"+rs.getString(1));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
事务
事务指的是一个业务操作, 假如某一个事务操作有两个步骤: 1.在末尾添加一个新值; 2.删除首部值.
没有使用事务时, 添加值和删除值是分两步完成的, 当其中某一个有问题时(比如某一个函数写错了), 另一个操作还是会完成.
使用事务之后, 要么两个操作都成功, 要么两个操作都失败.
c.setAutoCommit(false); //关闭自动提交
...
//业务代码
...
c.commit(); //手动提交
通过 c.setAutoCommit(false);关闭自动提交
使用 c.commit();进行手动提交
在Mysql中,只有当表的类型是INNODB的时候,才支持事务,所以需要把表的类型设置为INNODB,否则无法观察到事务.
修改表的类型为INNODB的SQL:
alter table hero ENGINE = innodb;
查看表的类型的SQL:
show table status from how2java;
ORM
ORM=Object Relationship Database Mapping
对象和关系数据库的映射
一个对象对应数据库里的一条记录(不绝对)
DAO
DAO=DataAccess Object
数据访问对象
运用了ORM的思路, 把数据库相关的操作都封装在这个类里面,其他地方看不到JDBC的代码.
数据库连接池
数据库连接池与线程池的概念类似