【实验目的】
(1)掌握MySQL数据库的安装和使用
(2)掌握通过JDBC方式操作数据库的基本步骤。
(3)掌握增、删、改、查记录的方法。
(4)学习MysqlDemo.java,完成简单的学生信息管理
【实验具体内容】
1.掌握MySQL数据库的安装和基本使用,在本机登录mysql后,利用GRANT授权法,实现远程访问数据库
服务器安装Mysql5.7,新建一个数据库名为sdujava,允许所有ip访问,放开服务器防火墙.
在IDEA中测试一下MysqlDemo.java.localhost改为服务器公网IP.
实验源程序: (MysqlDemo.java)
package Sixth;
import java.sql.*;
public class MysqlDemo {
public static void main(String[] args) throws SQLException {
Connection conn = null;
String sql;
String url = "jdbc:mysql://公网IP:3306/sdujava?"
+ "user=sdujava&password=ANkYKf6LdJznSaRt&useUnicode=true&characterEncoding=UTF8";
try {
// 之所以要使用下面这条语句,是因为要使用MySQL的驱动,所以我们要把它驱动起来,
// 可以通过Class.forName把它加载进去,也可以通过初始化来驱动起来,下面三种形式都可以
Class.forName("com.mysql.jdbc.Driver");// 动态加载mysql驱动
// or:
// com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver();
// or:
// new com.mysql.jdbc.Driver();
System.out.println("成功加载MySQL驱动程序");
// 一个Connection代表一个数据库连接
conn = DriverManager.getConnection(url);
// Statement里面带有很多方法,比如executeUpdate可以实现插入,更新和删除等
Statement stmt = conn.createStatement();
sql = "create table student(NO char(20),name varchar(20),primary key(NO))";
int result = stmt.executeUpdate(sql);// executeUpdate语句会返回一个受影响的行数,如果返回-1就没有成功
if (result != -1) {
System.out.println("创建数据表成功");
sql = "insert into student(NO,name) values('2012003','Java1')";
result = stmt.executeUpdate(sql);
sql = "insert into student(NO,name) values('2012004','Java2')";
result = stmt.executeUpdate(sql);
sql = "insert into student(NO,name) values('2012005','Java3')";
result = stmt.executeUpdate(sql);
sql = "select * from student";
ResultSet rs = stmt.executeQuery(sql);// executeQuery会返回结果的集合,否则返回空值
System.out.println("学号\t姓名");
while (rs.next()) {
System.out.println(rs.getString(1) + "\t" + rs.getString(2));// 入如果返回的是int类型可以用getInt()
}
}
} catch (SQLException e) {
System.out.println("MySQL操作错误");
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
conn.close();
}
}
}
实验运行结果:
2.学习MysqlDemo.java,熟悉GUI的同学可以编写一个简单的学生信息管理系统界面。如果不熟悉GUI,可以建立几个button来实现以下功能:
先创建student表,包含学生的学号、姓名、年龄信息。
① 点击“查询”按钮,根据学号,可以查询到学生的姓名和年龄;
② 点击“追加”按钮,根据给定的学生学号、姓名、年龄,在表中追加一行信息;
③ 点击“删除”按钮,利用给定的学生学号,可以从表中删除该学生的信息;
实验源程序:
package Sixth;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.awt.Color;
import java.awt.BorderLayout;
import java.awt.event.*;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JPanel;
import javax.swing.JLabel;
//这个类里面有6个方法,主方法main()必须是公共的,其他都是设置为了protected,体现一个权限概念;这些方法都设置成了静态的,这个类无需实例化就可以直接调用这些方法
public class Mysql extends JFrame implements ActionListener {
//给个序列号,保证对象串行化和存储
private static final long serialVersionUID= 1L;
/**按键*/
private final String[] KEYS={"查询","追加","删除","清框" };
/**按键的按钮*/
private JButton keys[]=new JButton[KEYS.length];
/**交互文本框*/
public JTextField interactText=new JTextField(" ");
/**提示标签*/
public JLabel label=new JLabel("<html><body><p align=\"center\">输入格式为'name.id.age'来追加一行新的学生信息<br/>输入id,点击查询来查询学生信息<br/>输入id,点击删除来删除学生信息</p></body></html>");
//创建静态全局变量
//因为几个方法都是静态的,在静态方法内部要使用这两个引用变量,所以他们也必须是静态的
static Connection conn;
static Statement st;
/**构造函数*/
public Mysql(){
//调用public JFrame(String title)构造方法,构造一个新的、最初不可见的、具有指定标题的 Frame 对象
super(" 学生信息管理系统");
init();
setBounds(300, 500, 500,500);
//用来设置此窗体是否可由用户调整大小,参数:resizable - 如果此窗体是可调整大小的,则为 true;否则为 false
this.setResizable(true);
//使得各个组件大小合适
this.pack();//调整此窗口的大小,以适合其子组件的首选大小和布局
}
protected void init(){
//创建一个新的面板
JPanel panel=new JPanel();
panel.setLayout(new GridLayout(1,4));
//把三个按钮组件放上去
for(int i=0;i<KEYS.length;i++){
//给这3个符号创建相应的按钮
keys[i]=new JButton(KEYS[i]);
//将key组件追加到此容器的尾部,加进到面板中
panel.add(keys[i]);
//设置符号的颜色
keys[i].setBackground(Color.black);
//设置符号的颜色
keys[i].setForeground(Color.white);
}
//建立一个画板放文本框
JPanel top =new JPanel();
//构造一个组件之间没有间距的新边框布局
top.setLayout(new BorderLayout());
top.add("Center",interactText);
//建立一个画板放提示标签
JPanel reminder =new JPanel();
//构造一个组件之间没有间距的新边框布局
top.setLayout(new BorderLayout());
reminder.add("Center",label);
//新建一个大的画板,把上面建立的画板放在该画板内
JPanel panel1=new JPanel();
//画板采用边界布局管理器,画板里组件之间的水平和垂直的方向上相隔都是3像素
//构造一个具有指定组件间距(水平间距为5,垂直间距也是5个像素)的边框布局
panel1.setLayout(new BorderLayout(10,10));
//将commands画板放在计算器的北部
panel1.add("North",reminder);
panel1.add("Center",interactText);
panel1.add("South",panel);
//整体布局,这段代码至关重要,没有就不会显示新建的这些面板和布局,这就体现了Frame的组成中一个非常重要的ContentPane,必须加进去才能被我们看到!!
getContentPane().setLayout(new BorderLayout(5,5));
getContentPane().add("North",top);
getContentPane().add("Center",panel1);
//结果左对齐显示
interactText.setHorizontalAlignment(JTextField.LEFT);
//先设置为不可以编辑,后面状态改成true,可以编辑就会触发 PropertyChange 事件("editable")
interactText.setEditable(true);
//文本框的颜色
interactText.setBackground(Color.lightGray);
//为各个按钮添加事件监听器
for(int i=0;i<KEYS.length;i++){
keys[i].addActionListener(this);
}
}
/**
* 处理事件
*/
//自定义的方法,组件发生动作时会产生事件,传递给这个对象
public void actionPerformed(ActionEvent e){
//获取事件源的标签
//当特定于组件的动作(比如被按下)发生时,由组件(比如 Button)生成此高级别事件。事件被传递给每一个 ActionListener 对象,这些对象是使用组件的 addActionListener 方法注册的,用以接收这类事,返回与此动作相关的命令字符串。
String label =e.getActionCommand();
//如果用户按了"查询"键
if (label.equals(KEYS[0])){
handleQuery();
}
//如果用户按了"追加"键
else if (label.equals(KEYS[1])){
handleInsert();
}
//如果用户按了"删除"键
else if (label.equals(KEYS[2])){
handleDelete();
}
//如果用户按了"清框"键
else if (label.equals(KEYS[3])){
handleClear();
}
}
/**
* 处理查询键被按下的事件
*/
private void handleQuery(){
String s=interactText.getText();
interactText.setText("");
conn = getConnection(); //同样先要获取连接,即连接到数据库
try {
// 查询数据的sql语句 ,*是通配符,代表所有的数据
String sql = "select * from studentinfo where id='"+s+"' ";
//String sql = "select * from studentinfo where name='"+s+"' ";
st = (Statement) conn.createStatement(); //创建用于执行静态sql语句的Statement对象,st属局部变量
ResultSet rs = st.executeQuery(sql); //执行sql查询语句,返回查询数据的结果集
while (rs.next()) { //这个while必须要有,没有就查询不出来
String name=rs.getString("name");
String id=rs.getString("id");
String age=rs.getString("age");
interactText.setText(name+"\t"+id+"\t"+age);
}
st.close() ;//关闭数据库连接
} catch (SQLException e) {
interactText.setText ("查询数据失败");
}
}
/**
* 处理追加键被按下的事件
*/
private void handleInsert(){
conn = getConnection(); // 首先要获取连接,即连接到数据库,得到的是一个Connection接口类的对象 ,因为是静态方法所以直接调用
String s=interactText.getText();
interactText.setText("");
//输入必须要用“name.id.age”这样的格式输入
String[] a=s.split("\\.");
for(int i=0;i<a.length;i++){
System.out.println(a[i]);
}
try {
// 插入数据的sql语句
String sql = "INSERT INTO studentinfo(name, id ,age)" + " VALUES ('"+a[0]+"','"+a[1]+"','"+a[2]+"')"; // 插入数据的sql语句
// 创建用于执行静态sql语句的Statement对象
st = (Statement) conn.createStatement();
// 执行插入操作的sql语句,并返回插入数据的个2数
st.executeUpdate(sql);
//立即释放此 Statement 对象的数据库和 JDBC 资源,这样可以避免对数据库资源的占用。
st.close() ;
//如果没有出现异常,插入成功以后就关闭数据库连接
conn.close();
interactText.setText("追加数据成功");
} catch (SQLException e) { //executeUpdate(sql)抛出了这个异常,所以要捕获
interactText.setText("追加数据失败" + e.getMessage());
System.out.println ("追加数据失败" + e.getMessage());
}
}
/**
* 处理删除键被按下的事件,删除符合要求的记录
*/
private void handleDelete(){
conn = getConnection(); //同样先要获取连接,即连接到数据库 ,这是自定义的函数
String s=interactText.getText();
interactText.setText("");
try {
// 删除该学号对应的信息的sql语句
String sql = "delete from studentinfo where id = '"+s+"'";
//创建用于执行静态sql语句的Statement对象,st属局部变量
st = (Statement) conn.createStatement();
// 执行sql删除语句,返回删除数据的数量
st.executeUpdate(sql);
//立即释放此 Statement 对象的数据库和 JDBC 资源,这样可以避免对数据库资源的占用。
st.close() ;
//关闭数据库连接
conn.close();
interactText.setText("删除数据成功");
} catch (SQLException e) {
System.out.println("删除数据失败");
interactText.setText("删除数据失败");
}
}
/**
* 处理清框键被按下的事件
*/
private void handleClear(){
interactText.setText("");
}
/* 自定义的获取数据库连接的函数*/
protected static Connection getConnection() { //用Connection接口类作为返回值类型,这个getConnection方法不是JdbcTest类的,而是这个Connection类的
Connection con = null; //创建用于连接数据库的Connection对象 ,只用于这个方法内部。局部变量
try { // 动态加载Mysql数据驱动,利用java.lang.Class类的forName方法,方法的参数是一个字符串,
//是类名 ,返回与带有给定字符串名的类或接口相关联的 Class 对象,所以也是实例化这个类
Class.forName("com.mysql.jdbc.Driver");//返回的这个对象怎么用?设时候用?有什么用?
//我新建的数据库叫做studentinfo,用户名和密码分别是root和JAVA
/*
useUnicode=true&characterEncoding=UTF8添加的作用是
指定字符的编码、解码格式。mysql数据库用的是gbk编码,而项目数据库用的是utf-8编码。这时候如果添加了useUnicode=true&characterEncoding=UTF-8 ,那么作用有如下两个方面:
存数据时:数据库在存放项目数据的时候会先用UTF-8格式将数据解码成字节码,然后再将解码后的字节码重新使用GBK编码存放到数据库中。
取数据时:在从数据库中取数据的时候,数据库会先将数据库中的数据按GBK格式解码成字节码,然后再将解码后的字节码重新按UTF-8格式编码数据,最后再将数据返回给客户端。
*/
con = DriverManager.getConnection( "jdbc:mysql://公网IP:3306/sdujava?"
+ "user=sdujava&password=7Sie4KRAEbdshtJT&useUnicode=true&characterEncoding=UTF8");
} catch (SQLException ex) {//getConnection()抛出了这个异常,在这里捕获
System.out.println("MySQL操作错误");
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
ex.printStackTrace();
} catch(ClassNotFoundException e){ //使用forName方法加载驱动有可能出现找不到类的异常
System.out.println("找不到驱动程序类 ,加载驱动失败!+e.getMessage()");
e.printStackTrace() ;
} catch (Exception e) { //保证对于所有的异常都一定有通道,所以在最后一个catch写最大的异常类
System.out.println("数据库连接失败" + e.getMessage());
}
return con; //返回所建立的数据库连接,一个Connection类的引用
}
public static void main(String[] args) {
Mysql jdbc=new Mysql();
//显示GUI界面
jdbc.setVisible(true);
jdbc.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
实验运行结果:
实验前,我已经在数据库中建立了一个名为sdujava的库,其中有一张表,表名叫做studentinfo,表中有三个字段,分别为name,id,age,分别对应学生姓名,学生学号和学生年龄.
其中的实验代码和老师给出的MysqlDemo,java差不多,不过是增加了一个字段,我就不展示了
最后的结果如下所示:
接下来运行程序:
程序运行界面如下:
追加信息后,数据库内容如下:
【实验心得】
1.任意IP都可访问
命令:
GRANT ALL PRIVILEGES ON *.* TO ‘root’@’%’ IDENTIFIED BY ‘password’ WITH GRANT OPTION;
/*字段解释:*.*:可访问所有数据库,可指定数据库;
‘root’:登陆用户名;
‘%’:任意IP可登陆;
password:为个人数据库登陆密码;
WITH GRANT OPTION;可赋予其他用户权限*/
2.指定IP可访问
GRANT ALL PRIVILEGES ON *.* TO ‘root’@’IP.%’ IDENTIFIED BY ‘password’ WITH GRANT OPTION;
/*字段解释:*.*:可访问所有数据库,可制定数据库;
‘root’:登陆用户名;
‘IP.%’:指定的IP可登陆,其他IP不行;
password:为个人数据库登陆密码;
WITH GRANT OPTION;可赋予其他用户权限*/
3.删除远程访问权限
直接删除对应的用户即可:
drop user 用户名@’%’;
记得每次创建或删除后运行以下命令,用于重新载入权限表:
flush privileges;
4.对varchar类的字段用一对单引号嵌套一对双引号,并且里面要用两个+把字段围起来,对于int型的变量就只需要一对单引号
5.Swing中的JLabel是支持基本的HTML代码的,
同样的JTextPane、JEditorPane也支持简单的HTML代码。
JLabel中换行是需要HTML的<br>标签进行换行的,不能用\n直接换行。
6. conn.close();必须写在try语句块里面,不能写在finally里面或者直接写在catch后面
7. protected static Connection getConnection() {····},定义方法在方法名前面加上java.sql的Connection接口类,是一个返回值类型,用类作为返回值类型,因为方法最后return了一个Connection类的引用,这个方法仍然是JdbcTest类的。
暂无评论内容