赞
踩
目录
使用Java连接MySQL之前需要先引入MySQL驱动jar包。
创建Java项目,并引入MySQL驱动jar包到项目中,如下图示例:
A、代码示例:
- //注册驱动:把驱动类加载到内存中
- //注意:5.1版本驱动包中驱动类名:com.mysql.jdbc.Driver
- //8.0版本驱动类名:com.mysql.cj.jdbc.Driver
- Class.forName("com.mysql.cj.jdbc.Driver");
-
- //与数据库建立连接
- Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/atguigu","root","1234");
-
- //实现增删改查数据
- //.....
-
- //关闭连接:如果不再使用连接需要断开连接以释放资源(底层是TCP/IP协议和IO流操作)
- conn.close();
- //程序能正常编译执行表示连接成功,如果抛异常表示连接失败。
B、步骤说明:
注册驱动
此步骤的目的是把驱动类加载到内存中,可以通过以下方式实现:
- //方式一:不推荐,因会导致注册驱动被执行两次(看源码),并且代码强依赖数据库驱动jar
- DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
-
- //方式二:创建了两个Driver对象(见源码),并且强依赖数据库驱动
- new com.mysql.cj.jdbc.Driver();
-
- //方式三:推荐,反射方式,接收字符串参数,降低了对驱动类的依赖
- Class.forName("com.mysql.cj.jdbc.Driver");
实际在JDK6之后
DriverManager
就已经可以实现自动注册驱动,如果手动注册了驱动,不再自动注册。但是仍然建议显示通过反射方式注册驱动。需要驱动包中此位置文件
META-INF/services/java.sql.Driver
中包含内容:com.mysql.cj.jdbc.Driver
与数据库建立连接
加载驱动程序后,可以使用DriverManager的重载方法getConnection
创建Connection对象,每个Connection对象表示Java程序与数据库之间的一个物理连接。
Connection conn = getConnection(String url,String user,String password);
其中不同数据库URL配置不同:
RDBMS | JDBC驱动程序名称 | URL格式 |
---|---|---|
MySQL | com.mysql.cj.jdbc.Driver | jdbc:mysql://hostname / databaseName |
ORACLE | oracle.jdbc.driver.OracleDriver | jdbc:oracle:thin:@ hostname:port Number:databaseName |
DB2 | com.ibm.db2.jdbc.net.DB2Driver | jdbc:db2:hostname:port Number / databaseName |
URL格式说明:
协议:子协议://主机名:端口/数据库名?参数名1=参数值1&参数名2=参数值2 其中,如果主机是本机或端口是默认3306端口时,可以缺省。如:jdbc:mysql:///databaseName
示例:jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=utf8(如果JDBC程序与服务器端的字符集不一致,会导致乱码,那么可以通过参数指定服务器端的字符集)
使用某些版本驱动包,建立连接时可能还需要设置服务器时区参数:
jdbc:mysql://localhost:3306/dbname?serverTimezone=Asia/Shanghai
三个重载方法创建连接示例:
- //方式一:
- Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testJDBC?user=root&password=1234");
-
- //方式二:
- Properties info = new Properties();
- info.setProperty("user", "root");
- info.setProperty("password", "1234");
- Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testJDBC",info);
-
- //方式三:(推荐方式)
- Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testJDBC","root","1234");
- /*
- 用JDBC实现添加一条记录到atguigu数据库的t_department表中。
- mysql> desc t_department;
- +-------------+--------------+------+-----+---------+----------------+
- | Field | Type | Null | Key | Default | Extra |
- +-------------+--------------+------+-----+---------+----------------+
- | did | int | NO | PRI | NULL | auto_increment |
- | dname | varchar(20) | NO | UNI | NULL | |
- | description | varchar(200) | YES | | NULL | |
- +-------------+--------------+------+-----+---------+----------------+
- 3 rows in set (0.01 sec)
- mysql> select * from t_department;
- +-----+--------+------------------+
- | did | dname | description |
- +-----+--------+------------------+
- | 1 | 研发部 | 负责研发工作 |
- | 2 | 人事部 | 负责人事管理工作 |
- | 3 | 市场部 | 负责市场推广工作 |
- | 4 | 财务部 | 负责财务管理工作 |
- | 5 | 后勤部 | 负责后勤保障工作 |
- | 6 | 测试部 | 负责测试工作 |
- +-----+--------+------------------+
- 6 rows in set (0.00 sec)
- 步骤:
- 1、注册驱动
- 2、获取数据库连接
- 3、获取Statement对象,用来执行sql
- 4、执行sql,即执行Statement对象的方法:int executeUpdate(),(增删改操作时)
- 5、释放资源
- */
- public class TestInsert {
- public static void main(String[] args)throws Exception {
- //1.注册驱动,把驱动类加载到内存中
- Class.forName("com.mysql.cj.jdbc.Driver");
- //2.创建数据库连接
- Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/atguigu","root","1234");
- //3.获取StateMent
- String sql = "insert into t_department values(null,'数据部门','数据部门简介')";
- PreparedStatement pst = conn.prepareStatement(sql);
- //4.执行SQL,插入数据,返回sql影响的记录数
- int len = pst.executeUpdate();
- System.out.println(len>0 ? "添加成功" : "添加失败");
- //5.释放资源
- pst.close();
- conn.close();
- /*
- mysql> select * from t_department;
- +-----+--------------+------------------+
- | did | dname | description |
- +-----+--------------+------------------+
- | 1 | 研发部 | 负责研发工作 |
- | 2 | 人事部 | 负责人事管理工作 |
- | 3 | 市场部 | 负责市场推广工作 |
- | 4 | 财务部 | 负责财务管理工作 |
- | 5 | 后勤部 | 负责后勤保障工作 |
- | 6 | 测试部 | 负责测试工作 |
- | 7 | 数据部门 | 数据部门简介 |
- +-----+--------------+------------------+
- 7 rows in set (0.00 sec)
- */
- }
- }

- public class TestUpdate {
- public static void main(String[] args)throws Exception {
- //1.把驱动类加载到内存中
- Class.forName("com.mysql.cj.jdbc.Driver");
- //2.获取数据库连接对象
- String url = "jdbc:mysql://localhost:3306/atguigu";
- Connection conn = DriverManager.getConnection(url, "root", "1234");
- //3.获取Statement对象
- String sql = "update t_department set description = 'xx' where did = 7";
- PreparedStatement pst = conn.prepareStatement(sql);
- //4.执行SQL,修改数据, 返回sql影响的记录数
- int len = pst.executeUpdate();
- System.out.println(len > 0 ? "修改成功" : "修改失败");
- //5.释放资源
- pst.close();
- conn.close();
- }
- }
- /*
- mysql> select * from t_department;
- +-----+--------------+------------------+
- | did | dname | description |
- +-----+--------------+------------------+
- | 1 | 研发部 | 负责研发工作 |
- | 2 | 人事部 | 负责人事管理工作 |
- | 3 | 市场部 | 负责市场推广工作 |
- | 4 | 财务部 | 负责财务管理工作 |
- | 5 | 后勤部 | 负责后勤保障工作 |
- | 6 | 测试部 | 负责测试工作 |
- | 7 | 测试数据部门 | xx |
- +-----+--------------+------------------+
- 7 rows in set (0.00 sec)
- */

- public class TestDelete {
- public static void main(String[] args)throws Exception {
- //1.把驱动类加载到内存中
- Class.forName("com.mysql.cj.jdbc.Driver");
- //2.获取数据库连接对象
- String url = "jdbc:mysql://localhost:3306/atguigu";
- Connection conn = DriverManager.getConnection(url, "root", "1234");
- //3.获取Statement对象
- String sql = "delete from t_department where did = 7";
- PreparedStatement pst = conn.prepareStatement(sql);
- //4.执行SQL,删除数据, 返回sql影响的记录数
- int len = pst.executeUpdate();
- System.out.println(len > 0 ? "删除成功" : "删除失败");
- //5.释放资源
- pst.close();
- conn.close();
- }
- }
- /*
- mysql> select * from t_department;
- +-----+--------+------------------+
- | did | dname | description |
- +-----+--------+------------------+
- | 1 | 研发部 | 负责研发工作 |
- | 2 | 人事部 | 负责人事管理工作 |
- | 3 | 市场部 | 负责市场推广工作 |
- | 4 | 财务部 | 负责财务管理工作 |
- | 5 | 后勤部 | 负责后勤保障工作 |
- | 6 | 测试部 | 负责测试工作 |
- +-----+--------+------------------+
- 6 rows in set (0.00 sec)
- */

- /*
- 步骤:
- 1、注册驱动
- 2、获取数据库连接
- 3、获取Statement对象,用来执行sql
- 4、执行sql,即执行Statement对象的方法:
- (1)int executeUpdate():执行insert,update,delete等更新数据库数据的sql
- (2)ResultSet executeQuery():执行select查询的sql,返回一个结果集
- (3)boolean execute():可以用来执行DDL语句
- 5、遍历结果集ResultSet:
- boolean next():判断是否还有下一行
- getObject(字段名或序号),getString(字段名或序号),getInt(字段名或序号)等
- 6、释放资源
- */
- public class TestSelect {
- public static void main(String[] args)throws Exception {
- //1.注册驱动,把驱动类加载到内存中
- Class.forName("com.mysql.cj.jdbc.Driver");
- //2.获取数据库连接对象
- String url = "jdbc:mysql://localhost:3306/atguigu";
- Connection conn = DriverManager.getConnection(url, "root", "1234");
- //3.获取Statement对象
- String sql = "select * from t_department";
- PreparedStatement pst = connn.prepareStatement(sql);
- //4.执行查询SQL,返回查询结果
- ResultSet resultSet = pst.executeQuery();
- //5.遍历结果集
- while(rs.next()){ //while循环一次,迭代一行,遍历一行
- int did = rs.getInt("did");//get一次得到一个单元格的数据
- String dname = rs.getString("dname");
- String decription = rs.getString("description");
- System.out.println(did +"\t" + dname +"\t" + decription);
- }
- //释放资源
- rs.close();
- pst.close();
- conn.close();
- }
- }

PrepareStatement接口是Statement的子接口,提供了更优秀的功能
返回值 | 方法名 | 含义 |
---|---|---|
ResultSet | executeQuery() | 执行预处理sql语句的查询操作 |
int | executeUpdate() | 执行预处理sql语句的增删改操作 |
void | setInt(int parameterIndex, int x) | 设置sql参数 |
void | setFloat(int parameterIndex, float x) | 设置sql参数 |
void | setString(int parameterIndex, String x) | 设置sql参数 |
void | setDate(int parameterIndex, java.sql.Date x) | 设置sql参数 |
void | setObject(int parameterIndex, Object x) | 设置sql参数 |
... | ... | ... |
(1)SQL语句拼接
- //提取用户名和密码变量,模拟登录操作
- String name = "tom";
- String password = "123456";
- String sql =
- "select * from users where name='" + name + "' and password='" + password + "'";
- System.out.println("sql="+sql);
-
- Statement stmt = conn.createStatement();
- ResultSet rs = stmt.executeQuery(sql);
(2)SQL注入
- String name = "tom";
- String password="' or '1'='1";// 如果登录时键盘录入密码为' or '1'='1时,结果登录成功
- String sql =
- "select * from users where name='" + name + "' and password='" + password + "'";
- System.out.println("sql="+sql);
-
- Statement stmt = conn.createStatement();
- ResultSet rs = stmt.executeQuery(sql);
(3)处理blob等类型的数据
如果数据库表中字段定义是blob类型时,需要写入的是二进制数据,即需要通过字节流写入二进制数据,这时无法把数据直接拼接成sql字符串。
(1)避免sql拼接
- String sql = "insert into users(name,password,email,birthday) values(?,?,?,?)";
- PreparedStatement pst = conn.prepareStatement(sql);//这里要传带?的sql,然后mysql端就会对这个sql进行预编译
-
- //设置?的具体值
- /*pst.setString(1, name);
- pst.setString(2, password);
- pst.setString(3, email);
- pst.setDouble(4, birthday);*/
-
- pst.setObject(1, name);
- pst.setObject(2, password);
- pst.setObject(3, email);
- pst.setObject(4, birthday);
-
- int len = pst.executeUpdate();//此处不能传sql
- System.out.println(len);

(2)不会有sql注入问题
- //即使输入' or '1'= '1也没问题
- String sql = "select * from users where name=? and password=?";
- String name = "tom";
- String password = "123123";
- PreparedStatement pstmt = conn.prepareStatement(sql);
-
- pstmt.setString(1,name );
- pstmt.setString(2,password );
- ResultSet rs = pstmt.executeQuery();
(3)处理blob类型的数据
- //pic字段为blob类型
- String sql = "insert into users(name,pic) value(?,?)";
- PreparedStatement pstmt = conn.prepareStatement(sql);
-
- pstmt.setString(1,"tom" );
- pstmt.setBlob(2,new FileInputStream("D:/1.jpeg"));
-
- int i = pstmt.executeUpdate();
- System.out.println(i > 0 ? "成功" : "失败");
注意两个问题:
①my.ini关于上传的字节流文件有大小限制,可以在my.ini中修改变量max_allowed_packet值
max_allowed_packet=16M
②每一种blob有各自大小限制:
tinyblob:255字节、blob:65k、mediumblob:16M、longblob:4G
采用转账案例
- /*
- * mysql默认每一个连接是自动提交事务的。
- * 那么当我们在JDBC这段,如果有多条语句想要组成一个事务一起执行的话,那么在JDBC这边怎么设置手动提交事务呢?
- * (1)在执行之前,设置手动提交事务
- * Connection的对象.setAutoCommit(false)
- * (2)成功:
- * Connection的对象.commit();
- * 失败:
- * Connection的对象.rollback();
- *
- * 补充说明:
- * 为了大家养成要的习惯,在关闭Connection的对象之前,把连接对象设置回自动提交
- * (3)Connection的对象.setAutoCommit(true)
- *
- * 因为我们现在的连接是建立新的连接,那么如果没有还原为自动提交,没有影响。
- * 但是我们后面实际开发中,每次获取的连接,不一定是新的连接,而是从连接池中获取的旧的连接,而且你关闭也不是真关闭,
- * 而是还给连接池,供别人接着用。以防别人拿到后,以为是自动提交的,而没有commit,最终数据没有成功。
- */
- public class TestTransaction {
- public static void main(String[] args) throws Exception{
- /*
- * 一般涉及到事务处理的话,那么业务逻辑都会比较复杂。
- * 例如:购物车结算时:
- * (1)在订单表中添加一条记录
- * (2)在订单明细表中添加多条订单明细的记录(表示该订单买了什么东西)
- * (3)修改商品表的销量和库存量
- * ...
- * 那么我们今天为了大家关注事务的操作,而不会因为复杂的业务逻辑的影响导致我们的理解,那么我们这里故意
- * 用两条修改语句来模拟组成一个简单的事务。
- * update t_department set description = 'xx' where did = 2;
- * update t_department set description = 'yy' where did = 3;
- *
- * 我希望这两条语句要么一起成功,要么一起回滚
- * 为了制造失败,我故意把第二条语句写错
- * update t_department set description = 'yy' (少了where) did = 3;
- */
-
- //1、注册驱动
- Class.forName("com.mysql.cj.jdbc.Driver");
-
- //2、获取连接
- Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "1234");
-
- //设置手动提交事务
- conn.setAutoCommit(false);
-
- //3、执行sql
- String sql1 = "update t_department set description = 'xx' where did = 2";
- String sql2 = "update t_department set description = 'yy' did = 3";//这句错的
-
- //使用prepareStatement的sql也可以不带问号?
- PreparedStatement pst = null;
- try {
- pst = conn.prepareStatement(sql1);
- int len = pst.executeUpdate();
- System.out.println("第一条:" + (len>0?"成功":"失败"));
-
- pst = conn.prepareStatement(sql2);
- len = pst.executeUpdate();
- System.out.println("第二条:" + (len>0?"成功":"失败"));
-
- //都成功了,就提交事务
- System.out.println("提交");
- conn.commit();
- } catch (Exception e) {
- System.out.println("回滚");
- //失败要回滚
- conn.rollback();
- }
-
- //4、关闭
- pst.close();
- conn.setAutoCommit(true);//还原为自动提交
- conn.close();
- }
- }

- /*
- * 我们通过JDBC往数据库的表格中添加一条记录,其中有一个字段是自增的,那么在JDBC这边怎么在添加之后直接获取到这个自增的值
- * PreparedStatement是Statement的子接口。
- * Statement接口中有一些常量值:
- * (1)Statement.RETURN_GENERATED_KEYS
- *
- * 要先添加后获取到自增的key值:
- * (1)PreparedStatement pst = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
- * (2)添加sql执行完成后,通过PreparedStatement的对象调用getGeneratedKeys()方法来获取自增长键值,遍历结果集
- * ResultSet rs = pst.getGeneratedKeys();
- */
- public class TestAutoIncrement {
- public static void main(String[] args) throws Exception{
- //1、注册驱动
- Class.forName("com.mysql.cj.jdbc.Driver");
-
- //2、获取连接
- Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
-
- //3、执行sql
- String sql = "insert into t_department values(null,?,?)";
- /*
- * 这里在创建PreparedStatement对象时,传入第二个参数的作用,就是告知服务器端
- * 当执行完sql后,把自增的key值返回来。
- */
- PreparedStatement pst = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
-
- //设置?的值
- pst.setObject(1, "测试部");
- pst.setObject(2, "测试项目数据");
-
- //执行sql
- int len = pst.executeUpdate();//返回影响的记录数
- if(len>0){
- //从pst中获取到服务器端返回的键值
- ResultSet rs = pst.getGeneratedKeys();
- //因为这里的key值可能多个,因为insert语句可以同时添加多行,所以用ResultSet封装
- //这里因为只添加一条,所以用if判断
- if(rs.next()){
- Object key = rs.getObject(1);
- System.out.println("自增的key值did =" + key);
- }
- }
-
- //4、关闭
- pst.close();
- conn.close();
- }
- }

- /*
- * 批处理:
- * 批量处理sql
- *
- * 例如:
- * (1)订单明细表的多条记录的添加
- * (2)批量添加模拟数据
- * ...
- *
- * 不用批处理,和用批处理有什么不同?
- * 批处理的效率很多
- *
- * 如何进行批处理操作?
- * (1)在url中要加一个参数
- * rewriteBatchedStatements=true,默认值false会发送多次sql请求
- * 那么我们的url就变成了 jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true
- * 这里的?,表示?后面是客户端给服务器端传的参数,多个参数直接使用&分割
- * (2)调用方法不同
- * pst.addBatch();
- * int[] all = pst.executeBatch();
- *
- * 注意:如果批量添加时,insert使用values,不要使用value,否则相当于发送多次sql执行
- */
- public class TestBatch {
-
- public static void main(String[] args) throws Exception{
- long start = System.currentTimeMillis();
- //例如:在部门表t_department中添加1000条模拟数据
- //1、注册驱动
- Class.forName("com.mysql.cj.jdbc.Driver");
-
- //2、获取连接
- Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true", "root", "123456");
-
- //3、执行sql
- String sql = "insert into t_department values(null,?,?)";
- PreparedStatement pst = conn.prepareStatement(sql);
-
- //设置?的值
- for (int i = 1; i <=1000; i++) {
- pst.setObject(1, "模拟部门"+i);
- pst.setObject(2, "模拟部门的简介"+i);
-
- pst.addBatch();//添加到批处理一组操作中,攒一块处理
- /* if(i % 500 == 0){//有时候也攒一部分,执行一部分
- //2.执行
- pst.executeBatch();
- //3.清空
- pst.clearBatch();
- }*/
- }
- //执行批处理操作
- pst.executeBatch();
-
- //4、关闭
- pst.close();
- conn.close();
-
- long end = System.currentTimeMillis();
- System.out.println("耗时:" + (end - start));//耗时:821
- }
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。