我们现在默认使用的都是root用户,超级管理员,拥有全部的权限。但是,一个公司里面的数据库服务器上面可能同时运行着很多个项目的数据库。所以,我们应该可以根据不同的项目建立不同的用户,分配不同的权限来管理和维护数据库。
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
关键字说明:
1. 用户名
:将创建的用户名
2. 主机名
:指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost,如果想让该用户可以从任意远程主机登陆,可以使用通配符%
3. 密码
:该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器
具体操作:
-- user1用户只能在localhost这个IP登录mysql服务器
CREATE USER 'user1'@'localhost' IDENTIFIED BY '123';
-- user2用户可以在任何电脑上登录mysql服务器
CREATE USER 'user2'@'%' IDENTIFIED BY '123';
授权格式:
GRANT 权限1, 权限2... ON 数据库名.表名 TO '用户名'@'主机名';
关键字说明:
1. GRANT
授权关键字
2. 授予用户的权限,如SELECT
,INSERT
,UPDATE
等。如果要授予所的权限则使用ALL
3. 数据库名.表名
:该用户可以操作哪个数据库的哪些表。如果要授予该用户对所有数据库和表的相应操作权限则可用*表示,如*.*
4. '用户名'@'主机名'
: 给哪个用户授权
具体操作:
给user1用户分配对test这个数据库操作的权限
GRANT CREATE,ALTER,DROP,INSERT,UPDATE,DELETE,SELECT ON test.* TO 'user1'@'localhost';
给user2用户分配对所有数据库操作的权限
GRANT ALL ON *.* TO 'user2'@'%';
REVOKE 权限1, 权限2... ON 数据库.表名 FROM '用户名'@'主机名';
具体操作:
SHOW GRANTS FOR '用户名'@'主机名';
具体操作:
DROP USER '用户名'@'主机名';
具体操作:
mysqladmin -uroot -p password 新密码 -- 新密码不需要加上引号
注意:需要在未登陆MySQL的情况下操作。
具体操作:
mysqladmin -uroot -p password 123456
输入老密码
set password for '用户名'@'主机名' = password('新密码');
注意:需要在登陆MySQL的情况下操作。
具体操作:
`set password for 'user1'@'localhost' = password('666666');`
客户端操作MySQL数据库的方式
什么是JDBC:Java Data Base Connectivity
(Java数据库连接) JDBC是Java访问数据库的标准规范
JDBC的作用:JDBC是用于执行SQL语句的Java API(Java语言通过JDBC可以操作数据库)
JDBC规范定义接口,具体的实现由各大数据库厂商来实现
JDBC是Java访问数据库的标准规范。真正怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个数据库厂商根据自家数据库的通信格式编写好自己数据库的驱动。所以我们只需要会调用JDBC接口中的方法即可。数据库驱动由数据库厂商提供。
JDBC的好处:
JDBC会用到的包:
JDBC四个核心对象
这几个类都是在java.sql包中
Connection
表示Java程序与数据库之间的连接,只有拿到Connection才能操作数据库。
JDBC获取连接步骤
1.导入驱动Jar包
2.注册驱动
3.获取连接
我们Java程序需要通过数据库驱动才能连接到数据库,因此需要注册驱动。
MySQL的驱动的入口类是:com.mysql.jdbc.Driver
java.sql.DriverManager
类用于注册驱动。提供如下方法注册驱动
static void registerDriver(Driver driver)
向 DriverManager 注册给定驱动程序。
1.DriverManager.registerDriver(驱动对象); 传入对应参数即可
public class Demo01 {
public static void main(String[] args) throws Exception {
// 注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
}
}
通过查询com.mysql.jdbc.Driver源码,我们发现Driver类“主动”将自己进行注册
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static {
try {
// 自己自动注册
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
public Driver() throws SQLException {
}
}
注意:使用
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
,存在两方面不足
- 硬编码,后期不易于程序扩展和维护
- 驱动被注册两次
使用Class.forName("com.mysql.jdbc.Driver");
加载驱动,这样驱动只会注册一次
public class Demo01 {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver"); // 后期可以将"com.mysql.jdbc.Driver"字符串写在文件中.
}
}
演示:Class.forName("包名.类名");
会走这个类的静态代码块
通常开发我们使用Class.forName() 加载驱动。Class.forName("com.mysql.jdbc.Driver");
会走Driver类的静态代码块。在静态代码块中注册一次驱动。
总结:注册MySQL驱动使用
Class.forName("com.mysql.jdbc.Driver");
java.sql.DriverManager
类中有如下方法获取数据库连接
static Connection getConnection(String url, String user, String password)
连接到给定数据库 URL ,并返回连接。
String url
:连接数据库的URL,用于说明连接数据库的位置String user
:数据库的账号String password
:数据库的密码连接数据库的URL地址格式:协议名:子协议://服务器名或IP地址:端口号/数据库名?参数=参数值
MySQL写法:jdbc:mysql://localhost:3306/day24
如果是本地服务器,端口号是默认的3306,则可以简写:jdbc:mysql:///day24
如果数据出现乱码需要加上参数: ?characterEncoding=utf8,表示让数据库以UTF-8编码来处理数据。
如: jdbc:mysql://localhost:3306/day24?characterEncoding=utf8
1.DriverManager.getConnection(url, user, password); 传入对应参数即可
public class Demo01 {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
// 连接到MySQL
// url: 连接数据库的URL
// user: 数据库的账号
// password: 数据库的密码
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day24", "root", "root");
System.out.println(conn);
}
}
我们要对数据库进行增、删、改、查,需要使用Statement
对象来执行SQL语句。
-- 创建分类表
CREATE TABLE category (
cid INT PRIMARY KEY AUTO_INCREMENT,
cname VARCHAR(100)
);
-- 初始化数据
INSERT INTO category (cname) VALUES('家电');
INSERT INTO category (cname) VALUES('服饰');
INSERT INTO category (cname) VALUES('化妆品');
在java.sql.Connection
接口中有如下方法获取到Statement
对象
Statement createStatement()
创建一个 Statement 对象来将 SQL 语句发送到数据库
boolean execute(String sql)
此方法可以执行任意sql语句。返回boolean值,表示是否返回ResultSet结果集。仅当执行select语句,且有返回结果时返回true, 其它语句都返回false;
int executeUpdate(String sql)
根据执行的DML(INSERT、UPDATE、DELETE)语句,返回受影响的行数
ResultSet executeQuery(String sql)
根据查询语句返回结果集,只能执行SELECT语句
注意:在MySQL中,只要不是查询就是修改。
executeUpdate:用于执行增删改
executeQuery:用于执行查询
public class Demo03 {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql:///day24", "root", "root");
System.out.println(conn);
// String sql = "SELECT * FROM category;";
// 从连接中拿到一个Statement对象
Statement stmt = conn.createStatement();
// 1.插入记录
String sql = "INSERT INTO category (cname) VALUES ('手机');";
int i = stmt.executeUpdate(sql);
System.out.println("影响的行数:" + i);
// 2.修改记录
sql = "UPDATE category SET cname='汽车' WHERE cid=4;";
i = stmt.executeUpdate(sql);
System.out.println("影响的行数:" + i);
// 3.删除记录
sql = "DELETE FROM category WHERE cid=1;";
i = stmt.executeUpdate(sql);
System.out.println("影响的行数:" + i);
// 释放资源
stmt.close();
conn.close();
}
}
ResultSet
用于保存执行查询SQL语句的结果。
我们不能一次性取出所有的数据,需要一行一行的取出。
ResultSet的原理:
ResultSet获取数据的API
其实ResultSet获取数据的API是有规律的get后面加数据类型。我们统称getXXX()
使用JDBC查询数据库中的数据的步骤
案例代码
public class Demo04 {
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql:///day24", "root", "root");
Statement stmt = conn.createStatement();
String sql = "SELECT * FROM category;";
ResultSet rs = stmt.executeQuery(sql);
// 内部有一个指针,只能取指针指向的那条记录
while (rs.next()) { // 指针移动一行,有数据才返回true
// 取出数据
int cid = rs.getInt("cid");
String cname = rs.getString("cname");
System.out.println(cid + " == " + cname);
}
// 关闭资源
rs.close();
stmt.close();
conn.close();
}
}
注意:
- 如果光标在第一行之前,使用rs.getXXX()获取列值,报错:Before start of result set
- 如果光标在最后一行之后,使用rs.getXXX()获取列值,报错:After end of result set
总结:其实我们使用JDBC操作数据库的步骤都是固定的。不同的地方是在编写SQL语句
- 注册驱动
- 获取连接
- 获取到Statement
- 使用Statement执行SQL
- ResultSet处理结果
- 关闭资源
之前我们是使用MySQL的命令来操作事务。接下来我们使用JDBC来操作银行转账的事务。
CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
balance DOUBLE
);
-- 添加数据
INSERT INTO account (NAME, balance) VALUES ('张三', 1000), ('李四', 1000);
Connection
接口中与事务有关的方法
void setAutoCommit(boolean autoCommit) throws SQLException;
false:开启事务, ture:关闭事务
void commit() throws SQLException;
提交事务
void rollback() throws SQLException;
回滚事务
public class Demo05 {
public static void main(String[] args) {
Connection conn = null;
try {
// 拿到连接
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql:///day24", "root", "root");
// 开启事务
conn.setAutoCommit(false);
Statement pstmt = conn.createStatement();
// 张三减500
String sql = "UPDATE account SET balance = balance - 500 WHERE id=1;";
pstmt.executeUpdate(sql);
// 模拟异常
// int i = 10 / 0;
// 李四加500
sql = "UPDATE account SET balance = balance + 500 WHERE id=2;";
pstmt.executeUpdate(sql);
pstmt.close();
// 成功,提交事务
System.out.println("成功,提交事务");
conn.commit();
} catch (Exception e) {
// 失败,回滚事务
try {
System.out.println("出了异常,回滚事务");
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
通过上面案例需求我们会发现每次去执行SQL语句都需要注册驱动,获取连接,得到Statement,以及释放资源。发现很多重复的劳动,我们可以将重复的代码定义到某个类的方法中。直接调用方法,可以简化代码。
那么我们接下来定义一个`JDBCUtil`类。把注册驱动,获取连接,得到Statement,以及释放资源的代码放到这个类的方法中。以后直接调用方法即可。
static Connection getConneciton();
close(Connection conn, Statement stmt, ResultSet rs)
close(Connection conn, Statement stmt)
JDBCUtils.java
public class JDBCUtils {
// 1.将固定字符串定义为常量
private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql:///day24";
private static final String USER = "root";
private static final String PASSWORD = "root";
// 2.在静态代码块中注册驱动(只注册一次)
// 当这个类加载到内存的时候就走这个静态代码块,再去触发Driver类中的静态代码块,主动注册
static {
try {
Class.forName(DRIVER_CLASS);
} catch (ClassNotFoundException e) {}
}
// 4.定义关闭资源的方法close(Connection conn, Statement stmt, ResultSet rs)
public static void close(Connection conn, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {}
}
}
}
模拟用户输入账号和密码登录网站
创建一个用户表保存用户的账号和密码,并添加一些数据,SQL语句如下:
CREATE TABLE USER (
id INT AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(50),
PASSWORD VARCHAR(50)
);
INSERT INTO USER (NAME, PASSWORD) VALUES('admin', '123'), ('test', '123'), ('gm', '123');
编写代码让用户输入账号和密码
public class Demo07 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入账号: ");
String name = sc.nextLine();
System.out.println("请输入密码: ");
String password = sc.nextLine();
}
使用SQL根据用户的账号和密码去数据库查询数据
public class Demo07 {
public static void main(String[] args) throws Exception {
// 让用户输入账号和密码
Scanner sc = new Scanner(System.in);
System.out.println("请输入账号: ");
String name = sc.nextLine();
System.out.println("请输入密码: ");
String password = sc.nextLine();
// 使用SQL根据用户的账号和密码去数据库查询数据
Connection conn = JDBCUtils.getConnection();
Statement stmt = conn.createStatement();
String sql = "SELECT * FROM user WHERE name='" + name + "' AND password='" + password + "';";
}
}
如果查询到数据,说明登录成功,如果查询不到数据,说明登录失败
public class Demo07 {
public static void main(String[] args) throws Exception {
// 让用户输入账号和密码
Scanner sc = new Scanner(System.in);
System.out.println("请输入账号: ");
String name = sc.nextLine();
System.out.println("请输入密码: ");
String password = sc.nextLine();
// 使用SQL根据用户的账号和密码去数据库查询数据
Connection conn = JDBCUtils.getConnection();
Statement stmt = conn.createStatement();
String sql = "SELECT * FROM user WHERE name='" + name + "' AND password='" + password + "';";
// 如果查询到数据,说明登录成功,如果查询不到数据,说明登录失败
ResultSet rs = stmt.executeQuery(sql);
if (rs.next()) {
//能进来查询到了数据.
String name2 = rs.getString("name");
System.out.println("欢迎您," + name2);
} else {
//查询不到数据,说明登录失败
System.out.println("账号或密码错误...");
}
JDBCUtils.close(conn, stmt, rs);
}
}