Java数据库编程技术
1. 建立数据库连接
例1.1 使用JDBC-ODBC桥来连接一个Access数据库。
该数据库的名称为FirstExample,在ODBC数据源中的名称为forStudy,用户名和密码均为空。
package connectDataBase; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class connect { public static void main(String[] args) { try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //加载数据库驱动 Connection con =DriverManager.getConnection("jdbc:odbc:forStudy","", ""); //这里是ODBC数据源名称 System.out.println("数据库连接成功!"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } }
2. 关闭数据库连接
例2.1 关闭数据库连接示例。
package connectDataBase; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class connect { public static void main(String[] args) { Connection con = null; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); //加载数据库驱动 con =DriverManager.getConnection("jdbc:odbc:forStudy","", ""); //这里是ODBC数据源名称 System.out.println("数据库连接成功!"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); }finally{ //在这里关闭数据库 if(con!=null){ try { if(!con.isClosed()) con.close(); //关闭数据库连接 System.out.println("数据库已关闭!"); } catch (SQLException e) { e.printStackTrace(); } } } } }
3. 添加新数据
一般将SQL语句存放在一个Statement对象中,然后先执行该对象的executeUpdate()方法就可以了。
例3.1 向数据库中添加新数据。
package connectDataBase; import java.sql.*; public class insertData { public static void main(String[] args) { Connection con = null; Statement sta; String sqlString = "insert into student values('30','小王','男','湖南湘潭','N-408','8293456')"; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:forStudy","",""); System.out.println("数据库连接成功!"); sta = con.createStatement(); sta.executeUpdate(sqlString); System.out.println("插入成功!"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if(con!=null){ try { if(!con.isClosed()) con.close(); System.out.println("数据库关闭!"); } catch (SQLException e) { e.printStackTrace(); } } } } }
一个可以接收用户输入的程序:
package connectDataBase; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.sql.*; public class insertData { public static void main(String[] args) { Connection con = null; Statement sta; String code,name,sex,address,room,tel; code = getInput("请输入编号: "); name = getInput("请输入姓名: "); sex = getInput("请输入性别: "); address = getInput("请输入地址: "); room = getInput("请输入寝室: "); tel = getInput("请输入电话: "); String sqlString = "insert into student values('"+code+"','"+name+"','"+sex+"','"+address+"','"+room+"','"+tel+"')"; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:forStudy","",""); System.out.println("数据库连接成功!"); sta = con.createStatement(); sta.executeUpdate(sqlString); System.out.println("插入成功!"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if(con!=null){ try { if(!con.isClosed()) con.close(); System.out.println("数据库关闭!"); } catch (SQLException e) { e.printStackTrace(); } } } } private static String getInput(String str) { String msg = ""; try { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.print(str); msg = br.readLine(); } catch (IOException e) { e.printStackTrace(); } return msg; } }
单纯地通过拼接字符串的方式将程序中的变量组合成标准的SQL语句是非常容易出错的,如果字符本身中还含有双引号或单引号,转化工作就会变的更为困难。所以,java又提供了一个PreparedStatement类,该类一个重要的作用就是提供了一个“占位符”,可以方便程序员进行转换的工作。
上面的程序可以改为:
package connectDataBase; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.sql.*; public class insertData { public static void main(String[] args) { Connection con = null; // Statement sta; PreparedStatement ps; String code,name,sex,address,room,tel; code = getInput("请输入编号: "); name = getInput("请输入姓名: "); sex = getInput("请输入性别: "); address = getInput("请输入地址: "); room = getInput("请输入寝室: "); tel = getInput("请输入电话: "); // String sqlString = "insert into student values('"+code+"','"+name+"','"+sex+"','"+address+"','"+room+"','"+tel+"')"; String sqlString = "insert into student values(?,?,?,?,?,?)"; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:forStudy","",""); System.out.println("数据库连接成功!"); // sta = con.createStatement(); // sta.executeUpdate(sqlString); ps = con.prepareStatement(sqlString); ps.setString(1, code); //替换第一个占位符 ps.setString(2, name); ps.setString(3, sex); ps.setString(4, address); ps.setString(5, room); ps.setString(6, tel); ps.executeUpdate(); System.out.println("插入成功!"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if(con!=null){ try { if(!con.isClosed()) con.close(); System.out.println("数据库关闭!"); } catch (SQLException e) { e.printStackTrace(); } } } } private static String getInput(String str) { String msg = ""; try { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.print(str); msg = br.readLine(); } catch (IOException e) { e.printStackTrace(); } return msg; } }
程序运行结果如下:
请输入编号: 0013 请输入姓名: 张三 请输入性别: 男 请输入地址: 河南郑州 请输入寝室: A-527 请输入电话: 8723641 数据库连接成功! 插入成功! 数据库关闭!
4. 删除数据
删除数据很简单,只要执行SQL语句中的删除命令delete即可。
package connectDataBase; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.sql.*; public class deleteData { public static void main(String[] args) { Connection con = null; Statement sta; String code= null; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:forStudy","",""); code = getInput("请输入要删除的学生编号: "); String sql = "delete from student where code='"+code+"'"; sta =con.createStatement(); int k = sta.executeUpdate(sql); System.out.println("删除了"+k+"条记录,编号为:"+code); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if(con!=null){ try { if(!con.isClosed()) con.close(); System.out.println("数据库关闭!"); } catch (SQLException e) { e.printStackTrace(); } } } } private static String getInput(String str) { String msg=null; try { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.print(str); msg = br.readLine(); } catch (IOException e) { e.printStackTrace(); } return msg; } }
程序运行结果如下:
请输入要删除的学生编号: 30 删除了1条记录,编号为:30 数据库关闭!
5. 修改数据
使用SQL语句中的update命令就可以修改数据,下面是个简单的例子,将所有性别为“男”的记录改成女。
例5.1 修改数据示例。
package connectDataBase; import java.sql.*; public class updateData { public static void main(String[] args) { Connection con = null; Statement sta; String sql; int k; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:forStudy", "", ""); System.out.println("数据库连接成功!"); sql ="update student set sex='女' where sex='男'"; sta = con.createStatement(); k = sta.executeUpdate(sql); System.out.println("修改了"+k+"条记录"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if(con!=null){ try { if(!con.isClosed()) con.close(); System.out.println("数据库关闭!"); } catch (SQLException e) { e.printStackTrace(); } } } } }
程序运行结果如下:
数据库连接成功!
修改了3条记录
数据库关闭!
6. 查询数据
利用SELECT语句查询得到结果后,会将结果放在一个ResultSet集中,遍历这个集合就可以做任何需要的操作。
例6.1 先用SQL查询获取一个结果集,然后遍历这个结果集,将其中的记录输出到屏幕。
package connectDataBase; import java.sql.*; public class queryData { public static void main(String[] args) { Connection con = null; Statement sta; ResultSet rs; String code,name,sex,address,room,tel; String sql; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:forStudy","",""); System.out.println("数据库连接成功!"); sta = con.createStatement(); sql = "select * from student"; rs = sta.executeQuery(sql); while(rs.next()){ code = rs.getString("code"); name = rs.getString("name"); sex = rs.getString("sex"); address = rs.getString("address"); room = rs.getString("room"); tel = rs.getString("tel"); System.out.println(code+" "+name+""+sex+" "+address+" "+room+" "+tel); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { if(con!=null){ try { if(!con.isClosed()) con.close(); System.out.println("数据库关闭!"); } catch (SQLException e) { e.printStackTrace(); } } } } }
程序运行结果如下:
数据库连接成功! 0001 陈永华女 湖南长沙 N-405 13107311256 0012 李明女 湖南株洲 S-102 8945211 0013 张三女 河南郑州 A-527 8723641 数据库关闭!
在上述程序中,需要先将游标执行一次next()方法,才能读取数据。这是因为游标开始的时候位于第一条记录的前面。
7. 学生信息管理系统实例
程序代码如下:
import java.awt.Container; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.sql.*; import javax.swing.*; public class AddressList extends WindowAdapter implements ActionListener { JFrame jf; Container con; JPanel jp[]; JTextField jtf[]; JLabel jl[]; JButton firstBtn,preBtn,nextBtn,lastBtn,addBtn,editBtn,delBtn,cancelBtn,saveBtn,searchBtn; Connection conn = null; Statement sta = null; ResultSet rs = null; protected int recordState = onlyRead, curRow = 0, recordCnt = 0; public static final int onlyRead = 0, adding = 1, amending = 2; public static final String lblmsg[]={"学生姓名","学籍号","身份证件号","性别","籍贯","民族", "家庭住址","学校名称","学校标识码","年级","班级","联系电话"}; private static final int fieldCnt = 12; //在构造方法中构造界面 public AddressList(){ jf = new JFrame("学籍信息管理系统"); con = jf.getContentPane(); con.setLayout(new BoxLayout(con,BoxLayout.Y_AXIS)); jp = new JPanel[7]; for(int i=0;i<7;i++){ jp[i] = new JPanel(); jp[i].setLayout(new FlowLayout()); } jtf = new JTextField[fieldCnt]; jl = new JLabel[fieldCnt]; for(int i=0;i<fieldCnt;i++){ jtf[i] = new JTextField(); jtf[i].setColumns(36); jtf[i].setEditable(false); jl[i] = new JLabel(); jl[i].setText(lblmsg[i]); jp[i/2].add(jl[i]); jp[i/2].add(jtf[i]); } firstBtn = new JButton("第一条"); firstBtn.addActionListener(this); preBtn = new JButton("上一条"); preBtn.addActionListener(this); nextBtn = new JButton("下一条"); nextBtn.addActionListener(this); lastBtn = new JButton("最后一条"); lastBtn.addActionListener(this); addBtn = new JButton("增加记录"); addBtn.addActionListener(this); editBtn = new JButton("编辑记录"); editBtn.addActionListener(this); delBtn = new JButton("删除记录"); delBtn.addActionListener(this); cancelBtn = new JButton("取消改变"); cancelBtn.addActionListener(this); saveBtn = new JButton("保存记录"); saveBtn.addActionListener(this); searchBtn = new JButton("查找记录"); //按身份证号查找 searchBtn.addActionListener(this); jp[6].add(firstBtn); jp[6].add(preBtn); jp[6].add(nextBtn); jp[6].add(lastBtn); jp[6].add(addBtn); jp[6].add(editBtn); jp[6].add(delBtn); jp[6].add(cancelBtn); jp[6].add(saveBtn); jp[6].add(searchBtn); for(int i=0;i<7;i++) con.add(jp[i]); jf.setSize(1000, 400); jf.setLocation(300, 200); // jf.setResizable(false); jf.setVisible(true); jf.addWindowListener(this); connection(); if(recordCnt>0) showData(); setFace(); } //打开数据库 public void connection() { // String path = this.getClass().getClassLoader().getResource("db/Student.mdb").getPath().substring(1); String path = "D:\\Student.mdb"; String url="jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ="+path; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // conn = DriverManager.getConnection("jdbc:odbc:Student", "", ""); conn = DriverManager.getConnection(url, "", ""); sta = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); rs = sta.executeQuery("select count(*) from student"); if(rs.next()) recordCnt = rs.getInt(1); //获取记录数 rs = sta.executeQuery("select * from student"); rs.next(); //将游标移动到第一条记录处 curRow = 1; } catch (ClassNotFoundException e) { JOptionPane.showMessageDialog(jf, "无法加载ODBC驱动"); } catch (SQLException e) { JOptionPane.showMessageDialog(jf, "数据库无法连接或没有记录"); } } //设置按钮的初始状态 protected void setFace(){ firstBtn.setEnabled(false); preBtn.setEnabled(false); nextBtn.setEnabled(true); lastBtn.setEnabled(true); addBtn.setEnabled(true); editBtn.setEnabled(true); delBtn.setEnabled(true); cancelBtn.setEnabled(false); saveBtn.setEnabled(false); } //退出系统时关闭数据库 public void windowClosing(WindowEvent e1){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } finally { System.exit(0); } } //依次在text中显示学生学籍信息(显示数据到控件中) public void showData(){ try { jtf[0].setText(rs.getString("name")); jtf[1].setText(rs.getString("stuID")); jtf[2].setText(rs.getString("IC")); jtf[3].setText(rs.getString("sex")); jtf[4].setText(rs.getString("native")); jtf[5].setText(rs.getString("nation")); jtf[6].setText(rs.getString("address")); jtf[7].setText(rs.getString("schname")); jtf[8].setText(rs.getString("schnum")); jtf[9].setText(rs.getString("grade")); jtf[10].setText(rs.getString("class")); jtf[11].setText(rs.getString("tel")); } catch (SQLException e) { JOptionPane.showMessageDialog(jf, "无法获取数据"); } } //几个辅助方法(供按钮调用) protected void setTextState(boolean flag){ //设置文本读写状态 for(int i=0;i<fieldCnt;i++) jtf[i].setEditable(flag); } protected void setTextEmpty(){ //将所有文本框中的数据清除 for(int i=0;i<fieldCnt;i++) jtf[i].setText(null); jtf[5].setText("汉族"); jtf[7].setText("确山县任店镇第二初级中学"); jtf[8].setText("3141002842"); } //"第一条"按钮事件响应代码 protected void doMoveFirst(){ //容错处理 if(curRow<=1){ firstBtn.setEnabled(false); preBtn.setEnabled(false); curRow = 1; return; } try { if(rs.first()){ //移动游标到第一条记录 showData(); //显示当前记录到界面上 curRow = 1; //记录游标的新位置 //重新设置按钮状态 firstBtn.setEnabled(false); preBtn.setEnabled(false); nextBtn.setEnabled(true); lastBtn.setEnabled(true); } } catch (SQLException e) { JOptionPane.showMessageDialog(jf, "移动游标出错"); } } //"上一条"按钮事件响应代码 protected void doMovePrevior(){ if(curRow<=1){ firstBtn.setEnabled(false); preBtn.setEnabled(false); curRow = 1; return; } try { if(rs.previous()){ //向前移动游标 showData(); curRow--; if(curRow==1){ //如果是第一条记录 firstBtn.setEnabled(false); preBtn.setEnabled(false); } nextBtn.setEnabled(true); lastBtn.setEnabled(true); } } catch (SQLException e) { JOptionPane.showMessageDialog(jf, "移动游标出错"); } } //"下一条"按钮事件响应代码 protected void doMoveNext(){ if(curRow>=recordCnt){ //容错处理 nextBtn.setEnabled(false); lastBtn.setEnabled(false); curRow=recordCnt; return; } try { if(rs.next()){ //向后移动游标 showData(); curRow++; if(curRow==recordCnt){ nextBtn.setEnabled(false); lastBtn.setEnabled(false); } firstBtn.setEnabled(true); preBtn.setEnabled(true); } } catch (SQLException e) { JOptionPane.showMessageDialog(jf, "移动游标出错"); } } //"最后一条"按钮事件响应代码 protected void doMoveLast() { if(curRow>=recordCnt){ //容错处理 nextBtn.setEnabled(false); lastBtn.setEnabled(false); curRow=1; return; } try{ if(rs.last()){ //将游标移动到最后 showData(); curRow=recordCnt; nextBtn.setEnabled(false); lastBtn.setEnabled(false); firstBtn.setEnabled(true); preBtn.setEnabled(true); } } catch(SQLException e) { JOptionPane.showMessageDialog(jf, "移动游标出错"); } } //增加记录按钮事件响应代码 protected void doAdd() { if(recordState==onlyRead){ //原先是浏览状态,现在切换到编辑状态 firstBtn.setEnabled(false); preBtn.setEnabled(false); nextBtn.setEnabled(false); lastBtn.setEnabled(false); addBtn.setEnabled(true); editBtn.setEnabled(false); delBtn.setEnabled(false); cancelBtn.setEnabled(true); saveBtn.setEnabled(true); recordState=adding; setTextState(true); //将各个Text置为可写 setTextEmpty(); //将各个Text置空,准备编辑记录 }else { //原先就是编辑状态 if(doSave(false)) //先保存上次增加的记录 setTextEmpty(); //如果保存成功,准备增加下一条记录 } } //保存记录按钮事件响应代码 protected boolean doSave(boolean goViewState) { try { if(recordState==amending){ //如果是修改状态 for(int i=0;i<fieldCnt;i++) rs.updateString(i+1, jtf[i].getText()); rs.updateRow(); //更新当前记录 goViewState = true; //准备切换到浏览状态 }else if(recordState==adding) { //这是增加状态 //将游标移动到准备插入的地方 rs.moveToInsertRow(); //下面3步是插入记录必备的 for(int i=0;i<fieldCnt;i++) rs.updateString(i+1, jtf[i].getText()); rs.insertRow(); recordCnt++; //修改记录数 curRow=recordCnt; //移动标志 rs.last(); //将游标移动到最后,也就是插入记录的位置 } } catch (SQLException e) { JOptionPane.showMessageDialog(jf, "保存数据不成功!"); return false; } if(goViewState){ //要切换回浏览状态 firstBtn.setEnabled(true); preBtn.setEnabled(true); nextBtn.setEnabled(false); lastBtn.setEnabled(false); addBtn.setEnabled(true); editBtn.setEnabled(true); delBtn.setEnabled(true); cancelBtn.setEnabled(false); saveBtn.setEnabled(false); recordState=onlyRead; setTextState(false); } return true; } //编辑记录按钮事件响应代码 protected void doEdit(){ if(0==recordCnt) return; //如果记录数为零,则不可能修改 //开始设置按钮的状态 firstBtn.setEnabled(false); preBtn.setEnabled(false); nextBtn.setEnabled(false); lastBtn.setEnabled(false); addBtn.setEnabled(false); editBtn.setEnabled(false); delBtn.setEnabled(false); cancelBtn.setEnabled(true); saveBtn.setEnabled(true); recordState = amending; //置为修改状态 setTextState(true); } //取消改变按钮事件响应代码 protected void doCancel(){ if(recordCnt==0) return; try { rs.absolute(curRow); //移动到原先记录处 showData(); //设置按钮状态 if(curRow>1){ firstBtn.setEnabled(true); preBtn.setEnabled(true); } if(curRow<recordCnt){ nextBtn.setEnabled(true); lastBtn.setEnabled(true); } addBtn.setEnabled(true); editBtn.setEnabled(true); delBtn.setEnabled(true); cancelBtn.setEnabled(false); saveBtn.setEnabled(false); recordState = onlyRead; setTextState(false); } catch (SQLException e) { JOptionPane.showMessageDialog(jf, "游标移动错误"); } } //删除记录按钮事件响应代码 protected void doDelete(){ if(0==recordCnt) return; //如果没有记录,则什么都不用做 if(JOptionPane.showConfirmDialog(jf, "删除后将不可恢复!确定要删除当前记录吗?","提示",JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION){ try { rs.deleteRow(); //删除当前记录 recordCnt--; if(recordCnt>0){ //如果剩余还有记录 if(curRow>=recordCnt) //如果删除的是最后一条记录 curRow=recordCnt; //否则的话,curRow的值无需改变,因为后一条记录自动成为了当前记录 rs.absolute(curRow); showData(); }else { curRow = 0; setTextEmpty(); } } catch (SQLException e) { JOptionPane.showMessageDialog(jf, "删除数据出错"); } } } //查找记录按钮事件响应代码 protected void doSearch(){ boolean b = true;; String IC = JOptionPane.showInputDialog(jf, "请输入要查找学生的身份证号:"); if(curRow<=1){ firstBtn.setEnabled(false); preBtn.setEnabled(false); curRow = 1; } try { if(rs.first()){ //移动游标到第一条记录 curRow = 1; //记录游标的新位置 //重新设置按钮状态 firstBtn.setEnabled(false); preBtn.setEnabled(false); nextBtn.setEnabled(true); lastBtn.setEnabled(true); } while(b&&IC!=null){ if(rs.getString("IC").equals(IC)){ try { jtf[0].setText(rs.getString("name")); jtf[1].setText(rs.getString("stuID")); jtf[2].setText(IC); jtf[3].setText(rs.getString("sex")); jtf[4].setText(rs.getString("native")); jtf[5].setText(rs.getString("nation")); jtf[6].setText(rs.getString("address")); jtf[7].setText(rs.getString("schname")); jtf[8].setText(rs.getString("schnum")); jtf[9].setText(rs.getString("grade")); jtf[10].setText(rs.getString("class")); jtf[11].setText(rs.getString("tel")); } catch (SQLException e) { JOptionPane.showMessageDialog(jf, "无法获取数据"); } return; }else{ if(curRow>=recordCnt){ curRow=recordCnt; b = false; JOptionPane.showMessageDialog(jf, "数据库中没找到该记录!"); } else{ if(rs.next()){ //向后移动游标 curRow++; if(curRow==recordCnt){ nextBtn.setEnabled(false); lastBtn.setEnabled(false); } firstBtn.setEnabled(true); preBtn.setEnabled(true); } } } } } catch (SQLException e) { JOptionPane.showMessageDialog(jf, "移动游标出错"); } } //actionPerformed()方法 public void actionPerformed(ActionEvent e){ Object obj; obj = e.getSource(); if(obj == firstBtn){ doMoveFirst(); }else if(obj == preBtn){ doMovePrevior(); }else if(obj == nextBtn){ doMoveNext(); }else if(obj==lastBtn){ doMoveLast(); }else if(obj==addBtn){ doAdd(); }else if(obj==saveBtn){ doSave(true); }else if(obj==editBtn){ doEdit(); }else if(obj==cancelBtn){ doCancel(); }else if(obj==delBtn){ doDelete(); }else if(obj==searchBtn){ doSearch(); } } public static void main(String[] args){ new AddressList(); } }