MySQL数据库和JDBC编程

作者:陆金龙    发表时间:2024-02-24 05:32   

关键词:  

来源:整理自李刚《疯狂Java讲义》。

1. 环境配置

将mysql-connector-java-5.1.30-bin.jar拷到JDK的lib目录下
在环境变量的classpath中加入路径:;%JAVA_HOME%\lib\mysql-connector-java-5.1.30-bin.jar”即可。
 

2. 数据库连接

public class ConnMySql
{
    public static void main(String[] args) throws Exception
    {
        // 1.加载驱动,使用反射的知识,现在记住这么写。
               Class.forName("com.mysql.jdbc.Driver");
        try(
        // 2.使用DriverManager获取数据库连接,
        // 其中返回的Connection就代表了Java程序和数据库的连接
               // 不同数据库的URL写法需要查驱动文档知道,用户名、密码由DBA分配
                Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root" , "kl123456");
        // 3.使用Connection来创建一个Statment对象
               Statement stmt = conn.createStatement();
        // 4.执行SQL语句
               /*
        Statement有三种执行sql语句的方法:
        1 execute 可执行任何SQL语句。- 返回一个boolean值,
          如果执行后第一个结果是ResultSet,则返回true,否则返回false
        2 executeQuery 执行Select语句 - 返回查询到的结果集
        3 executeUpdate 用于执行DML语句。- 返回一个整数,
          代表被SQL语句影响的记录条数
        */
        ResultSet rs = stmt.executeQuery("select s.* , teacher_name"+ " from student_table s , teacher_table t"+ " where t.teacher_id = s.java_teacher")) {
        // ResultSet有系列的getXxx(列索引 | 列名),用于获取记录指针
                // 指向行、特定列的值,不断地使用next()将记录指针下移一行,
                // 如果移动之后记录指针依然指向有效行,则next()方法返回true                while(rs.next()) {
                System.out.println(rs.getInt(1) + "\t"
                + rs.getString(2) + "\t"
                + rs.getString(3) + "\t"
                + rs.getString(4));
            }
        }){}
    }
}

3. DDL 建表

private String driver;
private String url;
private String user;
private String pass;

public void initParam(String paramFile) throws Exception{
    // 使用Properties类来加载属性文件
        Properties props = new Properties();
    props.load(new FileInputStream(paramFile));
    driver = props.getProperty("driver");
    url = props.getProperty("url");
    user = props.getProperty("user");
    pass = props.getProperty("pass");
}
public void createTable(String sql)throws Exception
{
    // 加载驱动
    Class.forName(driver);
    try(
    // 获取数据库连接
    Connection conn = DriverManager.getConnection(url , user , pass);
    // 使用Connection来创建一个Statment对象
    Statement stmt = conn.createStatement())
    {
        // 执行DDL,创建数据表
        stmt.executeUpdate(sql);
    }
}
public static void main(String[] args) throws Exception
{
    ExecuteDDL ed = new ExecuteDDL();
    ed.initParam("mysql.ini");
    ed.createTable("create table jdbc_test "
        + "( jdbc_id int auto_increment primary key, "
        + "jdbc_name varchar(255), "
        + "jdbc_desc text);");
    System.out.println("-----建表成功-----");
}

 

4.DML 插入数据

public int insertData(String sql)throws Exception
{
    // 加载驱动
    Class.forName(driver);
    try(
    // 获取数据库连接
    Connection conn = DriverManager.getConnection(url
    , user , pass);
    // 使用Connection来创建一个Statment对象
    Statement stmt = conn.createStatement())
    {
        // 执行DML,返回受影响的记录条数
        return stmt.executeUpdate(sql);
    }
}
public static void main(String[] args)throws Exception
{
    ExecuteDML ed = new ExecuteDML();
    ed.initParam("mysql.ini");
    int result = ed.insertData("insert into jdbc_test(jdbc_name,jdbc_desc)"
    + "select s.student_name , t.teacher_name "
    + "from student_table s , teacher_table t "
    + "where s.java_teacher = t.teacher_id;");
    System.out.println("--系统中共有" + result + "条记录受影响--");
}

5.执行SQL语句 (DDL、DML)

public void executeSql(String sql)throws Exception
{
    // 加载驱动
    Class.forName(driver);
    try(
    // 获取数据库连接
    Connection conn = DriverManager.getConnection(url
    , user , pass);
    // 使用Connection来创建一个Statement对象
    Statement stmt = conn.createStatement())
    {
        // 执行SQL,返回boolean值表示是否包含ResultSet
        boolean hasResultSet = stmt.execute(sql);
        // 如果执行后有ResultSet结果集
        if (hasResultSet)
        {
            try(
            // 获取结果集
            ResultSet rs = stmt.getResultSet())
            {
                // ResultSetMetaData是用于分析结果集的元数据接口
                ResultSetMetaData rsmd = rs.getMetaData();
                int columnCount = rsmd.getColumnCount();
                // 迭代输出ResultSet对象
                while (rs.next())
                {
                    // 依次输出每列的值
                    for (int i = 0 ; i < columnCount ; i++ )
                    {
                        System.out.print(rs.getString(i + 1) + "\t");
                    }
                    System.out.print("\n");
                }
            }
        }
        else
        {
            System.out.println("SQL语句影响的记录有"
                + stmt.getUpdateCount() + "");
        }
    }
}
public static void main(String[] args) throws Exception
{
    ExecuteSQL es = new ExecuteSQL();
    es.initParam("mysql.ini");
    System.out.println("------执行删除表的DDL语句-----");
    es.executeSql("drop table if exists my_test");
    System.out.println("------执行建表的DDL语句-----");
    es.executeSql("create table my_test"
        + "(test_id int auto_increment primary key, "
        + "test_name varchar(255))");
    System.out.println("------执行插入数据的DML语句-----");
    es.executeSql("insert into my_test(test_name) "
        + "select student_name from student_table");
    System.out.println("------执行查询数据的查询语句-----");
    es.executeSql("select * from my_test");
}

6. 预编译SQL

public void insertUseStatement()throws Exception
{
    long start = System.currentTimeMillis();
    try(
    // 获取数据库连接
    Connection conn = DriverManager.getConnection(url, user , pass);
    // 使用Connection来创建一个Statment对象
    Statement stmt = conn.createStatement())
    {
        // 需要使用100SQL语句来插入100条记录
        for (int i = 0; i < 100 ; i++ )
        {
            stmt.executeUpdate("insert into student_table values("+ " null ,'姓名" + i + "' , 1)");
        }
        System.out.println("使用Statement费时:"+ (System.currentTimeMillis() - start));
    }
}
public void insertUsePrepare()throws Exception
{
    long start = System.currentTimeMillis();
    try(
    // 获取数据库连接
       Connection conn = DriverManager.getConnection(url, user , pass);
    // 使用Connection来创建一个PreparedStatement对象
       PreparedStatement pstmt = conn.prepareStatement("insert into student_table values(null,?,1)"))
    {
        // 100次为PreparedStatement的参数设值,就可以插入100条记录
        for (int i = 0; i < 100 ; i++ )
        {
            pstmt.setString(1 , "姓名" + i);
            pstmt.executeUpdate();
        }
        System.out.println("使用PreparedStatement费时:"+ (System.currentTimeMillis() - start));
    }
}
public static void main(String[] args) throws Exception
{
    PreparedStatementTest pt = new PreparedStatementTest();
    pt.initParam("mysql.ini");
    pt.insertUseStatement();
    pt.insertUsePrepare();
}

7.防止SQL注入攻击


private boolean validate(String userName, String userPass)
{
    try(
    Connection conn = DriverManager.getConnection(url, user ,pass);
    PreparedStatement pstmt = conn.prepareStatement("select * from jdbc_test where jdbc_name=? and jdbc_desc=?")
)
    {
        pstmt.setString(1, userName);
        pstmt.setString(2, userPass);
        try(
        ResultSet rs = pstmt.executeQuery())
        {
            //如果查询的ResultSet里有超过一条的记录,则登录成功
            if (rs.next())
            {
                return true;
            }
        }
    }
catch(Exception e)
    {
        e.printStackTrace();
    }
    return false;
}

8. 调用存储过程


public void callProcedure()throws Exception
{
    // 加载驱动
    Class.forName(driver);
    try(
    // 获取数据库连接
    Connection conn = DriverManager.getConnection(url, user , pass);
    // 使用Connection来创建一个CallableStatment对象
    CallableStatement cstmt = conn.prepareCall("{call add_pro(?,?,?)}"))
    {
        cstmt.setInt(1, 4);
        cstmt.setInt(2, 5);
        // 注册CallableStatement的第三个参数是int类型
        cstmt.registerOutParameter(3, Types.INTEGER);
        // 执行存储过程
        cstmt.execute();
        // 获取,并输出存储过程传出参数的值。
        System.out.println("执行结果是: " + cstmt.getInt(3));
    }
}
public static void main(String[] args) throws Exception
{
    CallableStatementTest ct = new CallableStatementTest();
    ct.initParam("mysql.ini");
    ct.callProcedure();
}

9.管理结果集


public void query(String sql)throws Exception
{
    // 加载驱动
    Class.forName(driver);
    try(
    // 获取数据库连接
    Connection conn = DriverManager.getConnection(url , user , pass);
    // 使用Connection来创建一个PreparedStatement对象
    // 传入控制结果集可滚动,可更新的参数。
    PreparedStatement pstmt = conn.prepareStatement(sql
    , ResultSet.TYPE_SCROLL_INSENSITIVE
    , ResultSet.CONCUR_UPDATABLE);
    ResultSet rs = pstmt.executeQuery())
    {
        rs.last();
        int rowCount = rs.getRow();
        for (int i = rowCount; i > 0 ; i-- )
        {
            rs.absolute(i);
            System.out.println(rs.getString(1) + "\t"+ rs.getString(2) + "\t" + rs.getString(3));
            // 修改记录指针所有记录、第2列的值
                       rs.updateString(2 , "学生名" + i);
            // 提交修改
                       rs.updateRow();
        }
    }
}
public static void main(String[] args) throws Exception
{
    ResultSetTest rt = new ResultSetTest();
    rt.initParam("mysql.ini");
    rt.query("select * from student_table");
}
 

10.处理Blob类型数据


public class BlobTest
{
    JFrame jf = new JFrame("图片管理程序");
    private static Connection conn;
    private static PreparedStatement insert;
    private static PreparedStatement query;
    private static PreparedStatement queryAll;
    // 定义一个DefaultListModel对象
        private DefaultListModel imageModel= new DefaultListModel<>();
    private JList imageList = new JList<>(imageModel);
    private JTextField filePath = new JTextField(26);
    private JButton browserBn = new JButton("...");
    private JButton uploadBn = new JButton("上传");
    private JLabel imageLabel = new JLabel();
    // 以当前路径创建文件选择器
       JFileChooser chooser = new JFileChooser(".");
    // 创建文件过滤器
       ExtensionFileFilter filter = new ExtensionFileFilter();
    static
{
    try
{
    Properties props = new Properties();
    props.load(new FileInputStream("mysql.ini"));
    String driver = props.getProperty("driver");
    String url = props.getProperty("url");
    String user = props.getProperty("user");
    String pass = props.getProperty("pass");
    Class.forName(driver);
    // 获取数据库连接
    conn = DriverManager.getConnection(url , user , pass);
    // 创建执行插入的PreparedStatement对象,
    // 该对象执行插入后可以返回自动生成的主键
    insert = conn.prepareStatement("insert into img_table"+ " values(null,?,?)" , Statement.RETURN_GENERATED_KEYS);
    // 创建两个PreparedStatement对象,用于查询指定图片,查询所有图片
    query = conn.prepareStatement("select img_data from img_table"+ " where img_id=?");
    queryAll = conn.prepareStatement("select img_id, "+ " img_name from img_table");
}
catch (Exception e)
{
    e.printStackTrace();
}
}
public void init()throws SQLException
{
    // -------初始化文件选择器--------
    filter.addExtension("jpg");
    filter.addExtension("jpeg");
    filter.addExtension("gif");
    filter.addExtension("png");
    filter.setDescription("图片文件(*.jpg,*.jpeg,*.gif,*.png)");
    chooser.addChoosableFileFilter(filter);
    // 禁止“文件类型”下拉列表中显示“所有文件”选项。
    chooser.setAcceptAllFileFilterUsed(false);
    // ---------初始化程序界面---------
    fillListModel();
    filePath.setEditable(false);
    // 只能单选
    imageList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    JPanel jp = new JPanel();
    jp.add(filePath);
    jp.add(browserBn);
    browserBn.addActionListener(event -> {
        // 显示文件对话框
        int result = chooser.showDialog(jf , "浏览图片文件上传");
        // 如果用户选择了APPROVE(赞同)按钮,即打开,保存等效按钮
        if(result == JFileChooser.APPROVE_OPTION)
        {
            filePath.setText(chooser.getSelectedFile().getPath());
        }
    });
    jp.add(uploadBn);
    uploadBn.addActionListener(avt -> {
        // 如果上传文件的文本框有内容
        if (filePath.getText().trim().length() > 0)
        {
            // 将指定文件保存到数据库
            upload(filePath.getText());
            // 清空文本框内容
            filePath.setText("");
        }
    });
    JPanel left = new JPanel();
    left.setLayout(new BorderLayout());
    left.add(new JScrollPane(imageLabel) , BorderLayout.CENTER);
    left.add(jp , BorderLayout.SOUTH);
    jf.add(left);
    imageList.setFixedCellWidth(160);
    jf.add(new JScrollPane(imageList) , BorderLayout.EAST);
    imageList.addMouseListener(new MouseAdapter()
    {
        public void mouseClicked(MouseEvent e)
        {
            // 如果鼠标双击
            if (e.getClickCount() >= 2)
            {
                // 取出选中的List项
                ImageHolder cur = (ImageHolder)imageList.
            getSelectedValue();
                try
                {
                    // 显示选中项对应的Image
                    showImage(cur.getId());
                }
                catch (SQLException sqle)
                {
                    sqle.printStackTrace();
                }
            }
        }
    });
    jf.setSize(620, 400);
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jf.setVisible(true);
}
// ----------查找img_table填充ListModel----------
public void fillListModel()throws SQLException
{

    try(
    // 执行查询
    ResultSet rs = queryAll.executeQuery())
    {
        // 先清除所有元素
        imageModel.clear();
        // 把查询的全部记录添加到ListModel中
        while (rs.next())
        {
            imageModel.addElement(new ImageHolder(rs.getInt(1)
                ,rs.getString(2)));
        }
    }
}
// ---------将指定图片放入数据库---------
public void upload(String fileName)
{
    // 截取文件名
    String imageName = fileName.substring(fileName.lastIndexOf('\\')+ 1 , fileName.lastIndexOf('.'));
    File f = new File(fileName);
    try(
    InputStream is = new FileInputStream(f))
    {
        // 设置图片名参数
        insert.setString(1, imageName);
        // 设置二进制流参数
        insert.setBinaryStream(2, is , (int)f.length());
        int affect = insert.executeUpdate();
        if (affect == 1)
        {
            // 重新更新ListModel,将会让JList显示最新的图片列表
            fillListModel();
        }
    }
catch (Exception e)
    {
        e.printStackTrace();
    }
}
// ---------根据图片ID来显示图片----------
public void showImage(int id)throws SQLException
{
    // 设置参数
    query.setInt(1, id);
    try(
    // 执行查询
    ResultSet rs = query.executeQuery())
    {
        if (rs.next())
        {
            // 取出Blob列
            Blob imgBlob = rs.getBlob(1);
            // 取出Blob列里的数据
            ImageIcon icon=new ImageIcon(imgBlob.getBytes(1L,(int)imgBlob.length()));
            imageLabel.setIcon(icon);
        }
    }
}
public static void main(String[] args)throws SQLException
{
    new BlobTest().init();
}
}

11.分析结果集


// 根据用户输入的SQL执行查询
try(
    ResultSet rs = stmt.executeQuery(sqlField.getText()))
{
    // 取出ResultSetMetaData

    ResultSetMetaData rsmd = rs.getMetaData();
    Vector<String> columnNames =  new Vector<>();
    Vector<Vector<String>> data = new Vector<>();
    // ResultSet的所有列名添加到Vector    for (int i = 0 ; i < rsmd.getColumnCount(); i++ )
    {
        columnNames.add(rsmd.getColumnName(i + 1));
    }
    // ResultSet的所有记录添加到Vector    while (rs.next())
    {
        Vector<String> v = new Vector<>();
        for (int i = 0 ; i < rsmd.getColumnCount(); i++ )
        {
            v.add(rs.getString(i + 1));
        }
        data.add(v);
    }
    // 创建新的JTable
    JTable table = new JTable(data , columnNames);
    scrollPane = new JScrollPane(table);
    // 添加新的Table
    jf.add(scrollPane);
    // 更新主窗口
    jf.validate();
}
catch (Exception e)
{
    e.printStackTrace();
}