zoukankan      html  css  js  c++  java
  • JDBC

    JDBC连接数据库的方式

    方式一:

      public void test1() {
    	try {
    		Driver driver = new Driver();  //获得一个驱动
                     //连接数据看所需url,其中myemployees是所要连接的数据库
    		String url = "jdbc:mysql://localhost:3306/myemployees";
    		Properties properties = new Properties();
    		properties.setProperty("user", "root"); //user:用户名
    		properties.setProperty("password", "123456"); //password:密码
    		Connection conn = driver.connect(url,properties);
    		System.out.println(conn);
    	} catch (SQLException e) {
    		e.printStackTrace();
    	}
    }
    

    方式二

    public void test1() {
    	try {
    		//1.获取driver,通过反射实现
    		Class clazz = Class.forName("com.mysql.jdbc.Driver");
    		Driver driver = (Driver) clazz.newInstance();
    		//2.连接数据库
    		String url = "jdbc:mysql://localhost:3306/myemployees";
    		Properties properties = new Properties();
    		properties.setProperty("user", "root");
    		properties.setProperty("password", "123456");
    		Connection conn = driver.connect(url,properties);
    		System.out.println(conn);
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    }
    

    方式三

    public void test1() {
    	try {
    		//通过DriverManager类获得connection
    		String url = "jdbc:mysql://localhost:3306/myemployees";
    		Properties properties = new Properties();
    		properties.setProperty("user", "root");
    		properties.setProperty("password", "123456");
    		Connection conn = DriverManager.getConnection(url,properties);
    		System.out.println(conn);
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    }
    

    方式四(推荐)

    编写jdbc.properties配置文件

    //通过配置文件方式
    public void test1() {
    	try {
    		//通过当前类 获得类加载,进而加载文件
    		InputStream is = Conn.class.getClassLoader()
                              .getResourceAsStream("jdbc.properties");
    		Properties properties = new Properties();
    		properties.load(is);
    		// 读取配置文件信息
    		String user = properties.getProperty("user");
    		String password = properties.getProperty("password");
    		String url = properties.getProperty("url");
    		String driver = properties.getProperty("driver");
    		// 加载驱动
    		Class.forName(driver);
    		//获取连接
    		Connection conn = DriverManager.getConnection(url,user,password);
    		System.out.println(conn);
    			
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    }
    

    增删改查(CRUD)

    所用表

    编写连接数据库的工具类

    public class CRUDUtils {
    	//获取连接
    	public static Connection getConnection() {
    		Connection conn = null;
    		//1.加载文件
    		InputStream is = ClassLoader.getSystemClassLoader()
    				.getResourceAsStream("jdbc.properties");
    		Properties pro = new Properties();
    		try {
    			pro.load(is);
    			//2. 读取配置文件,获取数据
    			String user = pro.getProperty("user");
    			String password = pro.getProperty("password");
    			String url = pro.getProperty("url");
    			String driver = pro.getProperty("driver");
    			// 3.加载驱动
    			Class.forName(driver);
    			//4.获取连接
    			conn = DriverManager.getConnection(url, user, password);
    			
    		} catch (IOException e) {
    			e.printStackTrace();
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    		return conn;
    	}
    	
    	//关闭资源
    	public static void closeResource(Connection conn, PreparedStatement ps) {
    		if (conn != null) {
    			try {
    				conn.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    		if (ps != null) {
    			try {
    				ps.close();
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    

    增加数据的写法

    	/**
    	 * 增加用户
    	 */
    	public void addUser() {
    		// 1. 获取连接
    		Connection conn = CRUDUtils.getConnection();
    		PreparedStatement ps = null;
    		// 2. INSERT INTO USER VALUES(4,'user4','123',NOW())
    		String sql = "INSERT INTO USER VALUES(?,?,?,NOW())"; //所有字段
    		String sql2 = "INSERT INTO USER(id, birthday) values(?,?)"; //选择两个字段 
    		try {
    //			PreparedStatement ps = conn.prepareStatement(sql);
    //			ps.setInt(1, 4);
    //			ps.setString(2, "user4");
    //			ps.setString(3, "123");
    //			ps.execute();
    			//3. 获取prepareStatement对象
    		    ps = conn.prepareStatement(sql2);
    		    //4. 设置值
    			ps.setInt(1, 4); //插入id
    			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    			Date date = sdf.parse("2000-1-1");
                            //插入birthday,涉及java.util.date和java.sql.date日期转换
    			ps.setDate(2, new java.sql.Date(date.getTime())); 
    			//5.提交
    			ps.execute();
    		} catch (SQLException e) {
    			e.printStackTrace();
    		} catch (ParseException e) {
    			e.printStackTrace();
    		}finally {
    			//6.关闭
    			CRUDUtils.closeResource(conn, ps);
    		}
    	}
    

    修改数据的写法

    public void updateUser() {
    		//1. 获取连接
    		Connection conn = CRUDUtils.getConnection();
    		PreparedStatement ps = null;
    		try {
    			//2.预编译SQL语句,返回preparedStatement实例
    			String sql = "update user set username=? where id=?";
    			ps = conn.prepareStatement(sql);
    			//3.填充占位符
    			ps.setString(1, "abc");
    			ps.setInt(2, 1);
    			//4.提交
    			ps.execute();
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}finally {
                           //资源关闭
    			CRUDUtils.closeResource(conn, ps);
    		}
    	}
    

    查询数据
    编写一个Use人类

    import java.sql.Date;
    
    public class User {
    
    	private int id;
    	private String username;
    	private String password;
    	private Date birthday;
    	public User() {
    	}
    	public User(int id, String username, String password, Date birthday) {
    		super();
    		this.id = id;
    		this.username = username;
    		this.password = password;
    		this.birthday = birthday;
    	}
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getUsername() {
    		return username;
    	}
    	public void setUsername(String username) {
    		this.username = username;
    	}
    	public String getPassword() {
    		return password;
    	}
    	public void setPassword(String password) {
    		this.password = password;
    	}
    	public Date getBirthday() {
    		return birthday;
    	}
    	public void setBirthday(Date birthday) {
    		this.birthday = birthday;
    	}
    	@Override
    	public String toString() {
    		return "User [id=" + id + ", username=" + username + ", password=" + password + ", birthday=" + birthday + "]";
    	}
    	
    }
    
    

    通用查询

    /**
      通用查询
      Java属性和数据库列不一致时,可以为数据库列起别名
      同时获取列的别名时可以用md.getColumnLabel()方法。
    */
    public User queryUser(String sql, Object... args) {
    	// 1.获取连接
    	Connection conn  = CRUDUtils.getConnection();
    	PreparedStatement ps = null;
    	ResultSet rs = null;
    	try {
    		// 2.预编译sql,获取preparedStatement实例
    		ps = conn.prepareStatement(sql);
    		// 填充占位符
    		for(int i=0;i<args.length;i++) {
    			ps.setObject(i+1, args[i]);
    		}
    		// 3. 执行,并返回结果集
    		rs = ps.executeQuery();
    		ResultSetMetaData md = rs.getMetaData(); //获取结果集中的元素据
    		int columnCount = md.getColumnCount(); //获取结果集中列数
    		if (rs.next()) { //rs.next()查看是否存在下一条记录,类比iterate迭代器
    			//将数据封装到user对象中
    			User user = new User(); 
    			for(int i=0;i<columnCount;i++) {
    				//通过反射 给user字段赋值
    				//String columnName = md.getColumnName(i+1);//获取列名
                                    String columnLabel = md.getColumnLabel(i+1); //获取列的别名
    				Field field = User.class.getDeclaredField(columnLabel);
    				field.setAccessible(true); //访问
    				field.set(user,rs.getObject(i+1));
    			}
    			return user;
    		}
    		return null;
    	} catch (SQLException e) {
    		e.printStackTrace();
    	} catch (NoSuchFieldException e) {
    		e.printStackTrace();
    	} catch (SecurityException e) {
    		e.printStackTrace();
    	} catch (IllegalArgumentException e) {
    		e.printStackTrace();
    	} catch (IllegalAccessException e) {
    		e.printStackTrace();
    	}finally {
    		//4.关闭
    		CRUDUtils.closeResource(conn, ps, rs);
    	}
    	return null;
    }
    @Test //需要有Junit包
    public void test2() {
    	String sql = "select id,username,password,birthday from user "
    			+ "where username=? and password=?";
    	User queryUser = queryUser(sql, "user3", "1234");
    	System.out.println(queryUser);
    }
    

    preparedstatement相较于statement的好处

    • SQL注入问题,SQL语句写法不繁琐
    • PreparedStatement操作B1ob的数据,而Statement做不到。
    • PreparedStatement可以实现更高效的批量操作。

    存储blob类型数据

    • Blob:二进制对象。用于存储图片视频等
    public void blob() {
    	//1.获取连接
    	Connection conn = CRUDUtils.getConnection();
    	PreparedStatement ps = null;
    	try {
    		//2.获取PreparedStatement对象
    		String sql = "insert into user(id,username,password,photo)"
    				+ "values(?,?,?,?)";
    		ps = conn.prepareStatement(sql);
    		//填充占位符
    		ps.setInt(1, 5);
    		ps.setString(2, "aaa");
    		ps.setString(3, "123");
    		FileInputStream fis = new FileInputStream(new File("1.jpg"));
    		ps.setBlob(4, fis); // 该方法存储二进制对象
    		//提交
    		ps.execute();
    	} catch (SQLException e) {
    		e.printStackTrace();
    	} catch (FileNotFoundException e) {
    		e.printStackTrace();
    	}finally {
    		CRUDUtils.closeResource(conn, ps, null);
    	}
    }
    

    批量操作

    mysql默认不支持批量操作需要在url后面加上代码:rewriteBatchedStatements=true
    url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true

    /*
    * 批量操作
     */
    public void batch() {
    	//获取连接
    	Connection conn = CRUDUtils.getConnection();
    	PreparedStatement ps =  null;
    	//获取 实例
    	String sql = "insert into test1(name) values(?)";
    	try {
                    conn.setAutoCommit(false); //设置不允许自动提交
    		ps = conn.prepareStatement(sql);
    		for(int i=0;i<20;i++) {
    			ps.setString(1, "name"+i);
    			ps.addBatch(); //添加批量
    			if (i % 2000 == 0) {
    				ps.executeBatch(); //一次性送走2000条记录让SQL执行
    				ps.clearBatch(); //结束批量操作,下一波执行
    			}
    			ps.execute();
    		}
                    conn.commit(); //最后一次性提交,大大节省了时间
    	} catch (SQLException e) {
    		e.printStackTrace();
    	}finally {
    		CRUDUtils.closeResource(conn, ps, null);
    	}
    }
    

    事务的处理

    • DDL:数据定义语言,(创建create,删除truncaate/drop,修改alter表)
      set autocommit=false不起作用
    • DML:数据操作语言,(增insert,删delete,改update记录)
      天然的自动提交事务,一旦执行就提交,可以通过SQL语句:set autocommit=false,设置 不需要自动提交
    • 默认关闭连接 数据也会自动提交
    /**
     * 操作score表,实现AA向BB转账100
     */
    public void updateMoney(Connection conn, String sql, Object... args) {
    	PreparedStatement ps = null;
    	try {
    		//获取PreparedStatement实例
    		ps = conn.prepareStatement(sql);
    		for(int i=0;i<args.length;i++) {
    			ps.setObject(i+1,args[i]); //填充占位符
    		}
    		ps.execute(); //执行
    	} catch (SQLException e) {
    		e.printStackTrace();
    	}finally {
    		CRUDUtils.closeResource(null, ps, null); //关闭PreparedStatement资源
    	}
    }
    // A 转账给 B,转账完毕则关闭资源,中间阻塞,则数据回滚
    @Test
    public void test5() {
    	Connection conn = CRUDUtils.getConnection(); //获取Connection连接
    	try {
    		conn.setAutoCommit(false); //设置 不自动提交
    		String sqlA = "UPDATE score SET balance=balance-100 WHERE id=?";
    		updateMoney(conn, sqlA, 1); //A 取出100
    		System.out.println(10/0); //模拟阻塞
    		sqlA = "UPDATE score SET balance=balance+100 WHERE id=?";
    		updateMoney(conn, sqlA, 2);//B 得到100
    
                    conn.commit(); //事务提交
    	} catch (SQLException e) {
    		e.printStackTrace();
    		try {
    			conn.rollback(); //回滚
    		} catch (SQLException e1) {
    			e1.printStackTrace(); 
    		} 
    	} finally {			
    		CRUDUtils.closeResource(conn, null, null); //转账完毕则关闭Connection资源
    	}
    }
    

    事务并发问题

    • 脏读:对于两个事务T1,T2,T1读取了已经被T2更新但还没有被提交的字段。之后,若T2回滚,T1读取的内容就是临时且无效的。
    • 不可重复读:对于两个事务T1,T2,T1读取了一个字段,然后T2更新了该字段。之后,T1再次读取同一个字段,值就不同了。
    • 幻读:对于两个事务T1,T2,T1从一个表中读取了一个字段,然后T2在该表中插入了一些新的行。之后,如果T1再次读取同一个表,就会多出几行。

    隔离级别

    • READ UNCOMMITTED(读而未提交数据)
    • READ COMMITED(读已提交数据): 解决了脏读问题
    • REPEATABLE READ(可重复读): 解决了脏读和不可重复读问题
    • SERIALIZABLE(串行化): 解决了脏读,不可重复读,幻读的问题,但是性能十分低下。
      Oracle 只支持②和④的隔离级别,默认是②,而MySQL支持①,②,③,④的隔离级别,默认③

    数据库连接池

    看文档写代码

    //获取c3p0连接池
    ComboPooledDataSource cpds = new ComboPooledDataSource();
    //设置基本信息
    cpds.setDriverClass( "com.mysql.jdbc.Driver" ); //loads the jdbc driver            
    cpds.setJdbcUrl( "jdbc:mysql://localhost:3306/test" );
    cpds.setUser("root");                                  
    cpds.setPassword("123456");
    //获取连接
    Connection connection = cpds.getConnection();
    System.out.println(connection); //com.mchange.v2.c3p0.impl.NewProxyConnection@75412c2f
    
  • 相关阅读:
    nyoj 139 我排第几个--康拓展开
    树形dp--hdu 3534 Tree
    hdu 2196 Computer 树形dp模板题
    poj 2342 Anniversary party 简单树形dp
    hdu 4738 Caocao's Bridges 图--桥的判断模板
    poj 1144 Network 图的割顶判断模板
    poj 3159 Candies 差分约束
    poj 3169 Layout 差分约束模板题
    codeforces C. Triangle
    java中过滤器、监听器、拦截器的区别
  • 原文地址:https://www.cnblogs.com/huyuqing/p/14419114.html
Copyright © 2011-2022 走看看