java操作数据库的思想:连上数据库,发送sql语句。在连上数据库之前,要先用程序启动数据库,因此,可以通过反射加载类驱动(com.jdbc.mysql.Driver)。通过驱动管理类的静态方法传递数据库的url来获取一个连接对象(connection)。有三个重载的方法,第一个user和password都追加在url后(类似于get传参);第二种用逗号将user和passowrd隔开作为第二个和第三个参数;第三种通过配置文件Properties(方便修改,不用编译)。连接对象获取到表示数据库连接成功。 1.连接数据库。获得连接对象
public class Maintest { public static void main(String[] args) throws Exception { Class.forName("com.mysql.jdbc.Driver"); Properties p=new Properties(); p.load(new FileInputStream("E:\\IDEAJAVA\\Algorithm\\src\\test\\jdbc.properties")); Connection connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/test",p); System.out.println(connection); } }输出结果
com.mysql.jdbc.JDBC4Connection@26a1ab542.得到连接对象后就可以通过连接对象(connection)获得发送sql语句的对象(statement和PrepareStatement)。PrepareStatement相比Statement,可以进行预处理。就是先发送SQL语句,后发送参数。发送查询语句用executeQuery方法,会返回一个Resultset对象。该对象封装了查询出的结果集;发送其他语句可以用executeUpdate方法。该方法返回一个int类型的值,是影响了数据库的条数。 建表前的数据库:
mysql> use test Database changed mysql> show tables; Empty set (0.00 sec)建表的语句:
Statement statement=connection.createStatement();//获得发送语句的对象 String createTable="create table student(" //创建表的sql语句 + "id int not null auto_increment primary key," + "name varchar(20)," + "sex varchar not default 'M'" + ");"; statement.executeUpdate(createTable);//执行sql语句建表后在次查询收据库,表已建好。
mysql> show tables; Empty set (0.00 sec) mysql> show tables; +----------------+ | Tables_in_test | +----------------+ | student | +----------------+ 1 row in set (0.00 sec)3.插入数据:运用Statement和PrepareStatem两种类。
String insertData1="insert into student values(1,'zhangsan','M')";//statement的sql String insertData2="insert into student values(?,?,?)"; PreparedStatement preparedStatement=connection.prepareStatement(insertData2); statement.executeUpdate(insertData1);//执行插入数据 //设置参数 preparedStatement.setInt(1,2); preparedStatement.setString(2,"lisi"); preparedStatement.setString(3,"M"); System.out.println(preparedStatement.executeUpdate());//返回影响的行数结果返回1。再看数据库中的内容,插入成功。
mysql> select * from student; +----+----------+-----+ | id | name | sex | +----+----------+-----+ | 1 | zhangsan | M | | 2 | lisi | M | +----+----------+-----+ 2 rows in set (0.00 sec)4.查询:通过发送sql的对象(Statement和PreparStatemente),用executeQuery方法发送查询的sql语句,返回Resultset对象。executeUpdate方法不能发送查询语句,可以发送建表,修改表结构,插入数据,删除数据,修改数据。
Statement statement=connection.createStatement(); String query="select * from student"; ResultSet resultSet=statement.executeQuery(query);//返回查询结果 while(resultSet.next()) { System.out.println("id:"+resultSet.getInt(1)+"\tname:"+resultSet.getString(2)+"\tsex:"+resultSet.getString(3)); } System.out.println("--------------------------------------"); String querybyid="select * from student where id=?"; PreparedStatement preparedStatement=connection.prepareStatement(querybyid); preparedStatement.setInt(1,1);//查询id为1的学生的信息。 ResultSet resultSet1=preparedStatement.executeQuery(); while(resultSet1.next()) { System.out.println("id:"+resultSet1.getInt(1)+"\tname:"+resultSet1.getString(2)+"\tsex:"+resultSet1.getString(3)); }查询结果显示:
id:1 name:zhangsan sex:M id:2 name:lisi sex:M -------------------------------------- id:1 name:zhangsan sex:M5.批处理操作:通过addBatch方法向Statement对象中添加多个sql语句。再通过executeBatch方法执行每个SQL语句并返回每一条SQL语句执行后影响的行数。所以返回一个整型数组。但是批处理中不能放查询语句。
Statement statement=connection.createStatement(); statement.addBatch("insert into student values(3,\"luck\",\"F\");"); statement.addBatch("delete from student where id=1;"); System.out.println(Arrays.toString(statement.executeBatch()));返回结果为1,1。数据库查询结果:
mysql> select * from student; +----+------+-----+ | id | name | sex | +----+------+-----+ | 2 | lisi | M | | 3 | luck | F | +----+------+-----+ 2 rows in set (0.00 sec)6.ResultSetMetaData类,该类封装了一个查询结果ResultSet的基本信息,比如多少列、类型、建议名等。
Statement statement=connection.createStatement(); ResultSet resultSet=statement.executeQuery("select * from student"); ResultSetMetaData resultSetMetaData=resultSet.getMetaData(); for(int i=1;i<=resultSetMetaData.getColumnCount();i++) { System.out.print(resultSetMetaData.getColumnName(i)+"\t\t"); } System.out.println(); while(resultSet.next()) { System.out.println(resultSet.getInt(1)+"\t\t"+resultSet.getString(2)+"\t\t"+resultSet.getString(3)); }查询结果:
id name sex 2 lisi M 3 luck F7.事务:jdbc本身不支持事务,jdbc只是对事务做了简单的封装。还是用了数据库的事务。 事务四大特性:A(原子性)、C(一致性)、I(隔离性)、D(持久性)。 脏读:事务A读到了事务B修改单未提交的数据。 幻读:事务A第一次读到了符合条件的数据,事务B又添加了几条符合条件的数据,事务A再次读时,比第一次读到的多。出现幻读。 不可重复读:事务A读到数据后,事务B对数据进行修改,事务A再次读数据发现两次结果不一样。 针对以上三个问题出现以下四种隔离级别: 串行化(Serializable):级别最高,对事务串行执行,耗资源最大 重复读(repeatable read):保证了一个事务不会修改另一个事务已经读到的数据,避免了脏读和不可重复读。是大多数系统默认的隔离级别。 提交读(read commit):保证了一个事务不会读到一个已经修改但是还未提交的数据。只避免了脏读。 为提交读(read uncommitted):一个事务中的修改即使没有提交,其他事务也能查询到。一下是对事务的操作:
connection.setAutoCommit(false);//开启事务 try { statement.executeUpdate("insert into student values(4,\"abc\",\"M\");"); statement.executeUpdate("delete from student where id=5;");//库中没有id=5的学生。出现异常 connection.commit();//未出现异常时提交 } catch (SQLException e) { connection.rollback();//出现异常时撤回所有的操作 }finally { connection.close(); }因为出现异常,所有撤回所有的操作,因此在表中不能查到“abc”。将删除的id改为2后继续执行,这次不会出现异常,因此两句都被执行并提交。
mysql> select * from student; +----+------+-----+ | id | name | sex | +----+------+-----+ | 3 | luck | F | | 4 | abc | M | +----+------+-----+ 2 rows in set (0.00 sec)msyql支持四种隔离级别,隔离级别的查看与设置: 查看全局和会话事务的隔离级别
mysql> select @@global.tx_isolation,@@tx_isolation; +-----------------------+-----------------+ | @@global.tx_isolation | @@tx_isolation | +-----------------------+-----------------+ | REPEATABLE-READ | REPEATABLE-READ | +-----------------------+-----------------+ 1 row in set (0.00 sec)修改隔离级别:
mysql> set tx_isolation="serializable"; Query OK, 0 rows affected (0.11 sec) mysql> select @@global.tx_isolation,@@tx_isolation; +-----------------------+----------------+ | @@global.tx_isolation | @@tx_isolation | +-----------------------+----------------+ | REPEATABLE-READ | SERIALIZABLE | +-----------------------+----------------+ 1 row in set (0.00 sec)8.连接池:连接池内存放多个连接对象,当程序中需要用到时从中取出即可。不需要时,归还给连接池。实现连接对象的复用。连接池就是用来管理连接对象的。连接池要实现DataSource接口,该接口中有一个getConnection方法获得连接对象 c3p0连接池:下载c3p0的jar包,导入jar包。在src目录下加入c3p0.properties 配置文件。
public class Maintest { public static void main(String[] args) throws Exception { DataSource ds=new ComboPooledDataSource(); for(int i=0;i<10;i++) { Connection con=ds.getConnection(); System.out.println(con); con.close();//将连接对象归还给连接池 } } }配置文件内容
c3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql://localhost:3306/test c3p0.user=root c3p0.password=mysql c3p0.maxPoolSize=10 c3p0.minPoolSize=3Druid连接池:下载并导入jar包。Druid相比于c3p0来说,更加灵活。既可以通过配置文件来读连接数据库的信息,也可以通过程序来设定。
public class Maintest { public static void main(String[] args) throws Exception { DruidDataSource ds=new DruidDataSource(); //通过程序设定 ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3306/test"); //通过配置文件来设定。两种方式 // ResourceBundle rs=ResourceBundle.getBundle("jdbc"); // ds.setUsername(rs.getString("user")); // ds.setPassword(rs.getString("password")); Properties properties=new Properties(); properties.load(new FileReader("E:\\IDEAJAVA\\Algorithm\\src\\jdbc.properties")); ds.setUsername(properties.getProperty("user")); ds.setPassword(properties.getProperty("password")); ds.setInitialSize(3); ds.setMaxActive(10); Connection con=ds.getConnection(); System.out.println(con); } }以上代码建立了Druid连接池,通过程序设置了mysql的驱动,以及mysql的url。通过两种读取配置文件的方式来获取用户名和密码,再将其设置到连接池对象中。最后再通过程序设置连接池的初始容量以及最大个数。通过连接池获取对象,将对象输出。
