目录 (超全🕊️)
JDBC、Druid数据库连接池 和DBUtils
☄️ 满足你光速复习JDBC有关实用技巧直到并包含spring系列的JDBCTemplate。
☔ 忘了就来看,既有文档简洁也有笔记温度
1 JDBC数据库
1.1 JDBC数据库连接基础
JDBC(Java DataBase Connectivity)为访问不同数据库提供统一的接口,不同的数据库厂商实现接口。
java程序员只需要使用JDBC,就可以连接任何提供了JDBC驱动程序的数据库系统。本文使用mysql数据库
序号 | 程序编写步骤 |
---|---|
1 | 注册驱动 |
2 | 获取连接 |
3 | 执行操作 |
4 | 释放资源 |
1.2 JDBC 常用类的用法介绍
先看一眼,先了解就行。看到代码就懂了。先看代码也可(1.2.6 练习)。
包含sql注入、批处理、事务的操作。复习嘛,快就完了(哈哈),看api一下就想起来。想不起来的小笨蛋,看对应的代码。
1.2.1 Driver 驱动对象
注册两种方法
mysql5之后可以省略注册驱动的步骤,不需要通过DriverManager调用静态方法registerDriver()。
Driver类被加载就可以了。
1、new 一个driver实例
2、通过反射,进行类加载。class.forname(String classFullpath)
1.2.2 DriverManger 驱动管理对象
序号 | 方法 | 含义 |
---|---|---|
1 | static Connection getConnection(String url, String username, String password) | 获取连接Connection对象 url :jdbc:mysql://ip地址(域名):端口号/数据库名称 想实现批处理在url后加rewriteBatchedStatements=true user:数据库用户名 password:数据库密码 |
2-1 | setAutoCommit(boolean autoCommit) | 参数为false,则开启事务。 |
2-2 | commit() | 提交事务 |
2-3 | rollback() | 回滚事务 |
1.2.3 Connection 连接对象
序号 | 方法 | 含义 |
---|---|---|
1 | Statement createStatement(); | 获取普通执行对象,Statement对象,用来执行sql语句的对象。不防止sql注入,不建议使用 |
1 | PreparedStatement prepareStatement(String sql) | 获取预编译执行对象,PrepareStatement对象,用来执行sql语句的对象。有效防止sql注入,不建议使用 |
2 | void close(); | 释放资源,关闭连接。 |
1.2.4 Statement 普通执行对象
可以学习,但不推荐 。因为其不能防止sql注入。大多数情况被PrepareStatement对象代替。
序号 | 方法 | 含义 |
---|---|---|
1 | ResultSet executeQuery() | 执行DQL语句(select 语句)。根据查询返回封装了查询结果的对象,ResultSet对象。 |
2 | int executeUpdate() | 执行DML语句(create、delete、insert语句)。返回影响行数(返回大于0的数表示执行成功,反之sql语句执行失败) |
3 | void close() | 释放资源 |
1.2.4 PrepareStatement 预处理执行对象
预编译sql语句的执行者对象。在执行sql语句之前,将sql语句进行提前编译
明确sql语句的格式后,格式不会改变。内容整体都会认为是参数
能防止sql注入还能批量处理sql语句
序号 | 方法 | 含义 |
---|---|---|
1 | ResultSet executeQuery() | 执行DQL语句(select 语句)。根据查询返回封装了查询结果的对象,ResultSet对象。 |
2 | int executeUpdate() | 执行DML语句(create、delete、insert语句)。返回影响行数(返回大于0的数表示执行成功,反之sql语句执行失败) |
3 | void close() | 释放资源 |
4-1 | setAutoCommit(boolean autoCommit) | 开启事务 。参数为false,则开启事务。 |
4-2 | commit() | 提交事务 。 |
4-3 | rollback() | 回滚事务 。 |
5-1 | addBatch() | 添加需要批处理的sql语句 |
5-2 | executeBatch() | 执行批量处理语句 |
5-3 | clearBatch() | 清空批处理包的语句 |
1.2.5 ResultSet 查询结果封装对象
看一眼,看到代码就明白了。
表示查询结果集的数据表
ResultSet对象保持一个光标指向数据行,一行行的判断有无数据,下移光标读取。(next()方法和while配合)
序号 | 方法 | 含义 |
---|---|---|
1 | boolean next() | 判断是否还有数据。 true:有数据,并将索引下移 |
2 | void close() | 释放资源 |
3 | String getString(String name) | 返回字符串。获取改行数据列名为name的字符串 还有很多类似放方法。想返回什么类型数据"get数据类型"=。大同小异,具体查看API |
4 | String getString(int index) | index 从1开始,作用与上一致 |
1.2.6 练习
实现代码,说穿就是API。照着前面列好的API看
mysqlLogin.properties
user=root
url=jdbc\:mysql\://localhost\:3306/revJ?rewriteBatchedStatements=true
password=mima
driver=com.mysql.jdbc.Driver
Properties properties = new Properties();
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
properties.load(new FileInputStream("./mysqlLogin.properties"));
String classFullPath = properties.getProperty("driver");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
//一、动态加载Driver
Class.forName(classFullPath);
//二、获取连接 通过DriverManger
connection = DriverManager.getConnection(url, user, password);
//三、数据库操作 执行查找操作
String sql = "select * from test1 where id > ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 2);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
int id = resultSet.getInt(1);
String name = resultSet.getString("name");
System.out.printf("id=%d,name=%s\n", id, name);
}
// String sql = "insert into test1 value(?,?)";
// preparedStatement = connection.prepareStatement(sql);
// preparedStatement.setInt(1,9);
// preparedStatement.setString(2,"yu9");
// int effectRowNum = preparedStatement.executeUpdate();
// System.out.println(effectRowNum>0?String.format("执行成功,影响%d行",effectRowNum):"执行失败");
} catch (IOException | ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
//四、释放资源
try {
if (resultSet != null) {
resultSet.close();
}
if (preparedStatement != null) {
preparedStatement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
System.out.println("---结束---");
1.3 批处理
真有小笨蛋,看api想不来呀,呜呜,好吧。我也一样。上代码。
url后要加 rewriteBatchedStatements=true
String sql = "insert into test1 value(?,?)";
preparedStatement = connection.prepareStatement(sql);
//批量添加数据 向test1表种添加50条数据
for (int i = 1; i <= 50; i++) {
preparedStatement.setInt(1,i);
preparedStatement.setString(2,"yu"+i);
//1、addBatch()
preparedStatement.addBatch();
//2、executeBatch()
//3、clearBatch()
if(i%10==0) {
preparedStatement.executeBatch();
preparedStatement.clearBatch();
}
}
1.4 事务
Properties properties = new Properties();
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
properties.load(new FileInputStream("./mysqlLogin.properties"));
String classFullPath = properties.getProperty("driver");
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
Class.forName(classFullPath);
connection = DriverManager.getConnection(url, user, password);
//1、看这里 根注释走
connection.setAutoCommit(false);
String sql = "insert into test1 value(?,?)";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 51);
preparedStatement.setString(2, "yu51");
int effectRowNum = preparedStatement.executeUpdate();
//故意出现异常、测试是否会回滚事务
//会失败(我设计的)异常会导致事务回滚
int cuo = 10 /0;
//3、 事务提交
connection.commit();
} catch (Exception e) {
e.printStackTrace();
//2、事务回滚
connection.rollback();
System.out.println("执行失败");
} finally {
try {
if (resultSet != null) {
resultSet.close();
}
if (preparedStatement != null) {
preparedStatement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
System.out.println("---结束---");
1.5 JDBC utils
使用JDBC的基本代码不会变,每次用都写一样的代码,啰嗦!封装起来,下次还能用。
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
/**
* @author Jyu
* @version 1.0
*/
public class JDBCUtils {
private static String user;
private static String password;
private static String url;
private static String driver;
static {
Properties properties = new Properties();
try {
properties.load(new FileInputStream("./mysqlLogin.properties"));
user = properties.getProperty("user");
password = properties.getProperty("password");
url = properties.getProperty("url");
driver = properties.getProperty("driver");
Class.forName(driver);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static Connection getConnection() {
try {
return DriverManager.getConnection(url,user,password);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static void close(ResultSet resultSet, Statement statement, Connection connection) {
try {
if(resultSet != null) {
resultSet.close();
}
if(statement != null) {
statement.close();
}
if(connection!= null) {
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
2 数据库连接池
2.1 数据库c3p0
我们用到:
- c3p0-0.9.1.2.jar
c3p0-config.xml
<c3p0-config>
<!-- 数据源的名称代表连接池 -->
<named-config name="hello">
<!-- 驱动类 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<!-- url-->
<!-- url=jdbc:mysql://ip:端口/数据库名 -->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/girls</property>
<!-- 用户名 -->
<property name="user">root</property>
<!-- 密码 -->
<property name="password">root</property>
<!-- 每次增长的连接数-->
<property name="acquireIncrement">5</property>
<!-- 初始的连接数 -->
<property name="initialPoolSize">10</property>
<!-- 最小连接数 -->
<property name="minPoolSize">5</property>
<!-- 最大连接数 -->
<property name="maxPoolSize">10</property>
<!-- 可连接的最多的命令对象数 -->
<property name="maxStatements">5</property>
<!-- 每个连接对象可连接的最多的命令对象数 -->
<property name="maxStatementsPerConnection">2</property>
</named-config>
</c3p0-config>
获取连接方式
//1. 将 c3p0 提供的 c3p0.config.xml 拷贝到 src 目录
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("hello");
Connection connection = comboPooledDataSource.getConnection();
2.2Druid 数据库连接池
我们用到:
- druid-1.1.10.jar
druid.properties
#key=value
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/revj?rewriteBatchedStatements=true
#url=jdbc:mysql://ip:端口/数据库名
username=root
password=ysk
#initial connection Size
initialSize=10
#min idle connecton size
minIdle=5
#max active connection size
maxActive=20
#max wait time (5000 mil seconds)
maxWait=5000
获取连接方式
Properties properties = new Properties();
properties.load(new FileInputStream("src/druid.properties"));
//1、看这里
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
Connection connection = dataSource.getConnection();
2.3JDBCUtilsByDruid
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* @author xiaoyu
* @version 1.0
*/
public class JDBCUtilsByDruid {
private static DataSource dataSource;
//dataSource初始化
static {
try {
Properties properties = new Properties();
//properties.load(new FileInputStream("src\\druid.properties"));
properties.load(JDBCUtilsByDruid.class.getClassLoader().getResourceAsStream("druid.properties"));
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void close(ResultSet resultSet, Statement statement, Connection connection) {
try {
if(resultSet != null) {
resultSet.close();
}
if(statement != null){
statement.close();
}
if(connection != null) {
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
3 Apache—DBUtils
我们用到
- commons-dbutils-1.3.jar
3.1QueryRunner
序号 | 方法 | 含义 |
---|---|---|
1 | public T query(Connection conn, String sql, ResultSetHandler rsh, Object… params) | 执行DQL语句(select 语句) ResultSetHandler是一个接口,参数是一个其实现类对象 Object… param :就是给 sql 语句中的? 赋值,可以有多个值,所以是可变参数 |
2 | public int update(Connection conn, String sql, Object… params) | 执行DML语句(create、delete、insert语句) |
3 | public int[] batch(Connection conn, String sql, Object[] []params) | 批处理 |
3.2 ResultSetHandler接口
BeanHandler 将查询结果的一行封装到javaBean对象
Bean ListHandler 将查询结果的每一行封装到javaBean对象,然后再存入List集合
ScalerHandler 将结果集第一行的某一列放到某个对象中
…
还有很多,根据需要看api吧
3.3 BasicDAO
import TestDurid.utils.JDBCUtilsByDruid;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* @author xiaoyu
* @version 1.0
* BasicDAO 是其他类的父类
*/
public class BasicDAO<T> { //泛型指定具体类型
private QueryRunner queryRunner = new QueryRunner();
//开发通用的dml方法, 针对任意的表
public int update(String sql,Object... parameters){
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return queryRunner.update(connection,sql,parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(null, null, connection);
}
}
public Object queryScalar(String sql, Object... parameters){
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return queryRunner.query(connection,sql,new ScalarHandler(),parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(null, null, connection);
}
}
public T querySingle(String sql,Class<T> clazz, Object... parameters) {
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return queryRunner.query(connection,sql, new BeanHandler<T>(clazz),parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(null,null,connection);
}
}
public List<T> queryMulti(String sql,Class<T> clazz, Object... parameters){
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return queryRunner.query(connection,sql,new BeanListHandler<T>(clazz),parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JDBCUtilsByDruid.close(null, null, connection);
}
}
}
4 JavaWeb事务
javaWeb中的使用,利用过滤器
4.1TransactionFilter
public class TransactionFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
filterChain.doFilter(servletRequest,servletResponse);
JDBCUtilsByDruid.commit();
} catch (Exception e) {
JDBCUtilsByDruid.rollBack();
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Override
public void destroy() {
}
}
4.2 JDBCUtilsByDruid
package com.jyu.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* @author xiaoyu
* @version 1.0
*/
public class JDBCUtilsByDruid {
private static DataSource dataSource;
private static ThreadLocal<Connection> threadLocalConnection = new ThreadLocal<>();
//dataSource初始化
static {
try {
Properties properties = new Properties();
properties.load(JDBCUtilsByDruid.class.getClassLoader().getResourceAsStream("druid.properties"));
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
Connection connection = threadLocalConnection.get();
if(connection == null ){
try {
connection = dataSource.getConnection();
connection.setAutoCommit(false);
} catch (SQLException e) {
throw new RuntimeException(e);
}
threadLocalConnection.set(connection);
}
return connection;
}
public static void commit(){
Connection connection = threadLocalConnection.get();
if(connection != null){
try {
connection.commit();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
threadLocalConnection.remove();
}
}
public static void rollBack(){
Connection connection = threadLocalConnection.get();
if(connection != null){
try {
connection.rollback();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
threadLocalConnection.remove();
}
public static void close(ResultSet resultSet, Statement statement, Connection connection) {
try {
if(resultSet != null) {
resultSet.close();
}
if(statement != null){
statement.close();
}
if(connection != null) {
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
4.3 BasicDAO
package com.jyu.dao;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import com.jyu.utils.JDBCUtilsByDruid;
/**
* @author xiaoyu
* @version 1.0
* BasicDAO(事务) 是其他类的父类
*/
public class BasicDAO<T> { //泛型指定具体类型
private QueryRunner queryRunner = new QueryRunner();
//开发通用的dml方法, 针对任意的表 sql增、删、改语句
public int update(String sql,Object... parameters){
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return queryRunner.update(connection,sql,parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public Object queryScalar(String sql, Object... parameters){
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return queryRunner.query(connection,sql,new ScalarHandler(),parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public T querySingle(String sql,Class<T> clazz, Object... parameters) {
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return queryRunner.query(connection,sql, new BeanHandler<T>(clazz),parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public List<T> queryMulti(String sql,Class<T> clazz, Object... parameters){
Connection connection = null;
try {
connection = JDBCUtilsByDruid.getConnection();
return queryRunner.query(connection,sql,new BeanListHandler<T>(clazz),parameters);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
5 JDBCTemplate
这里要思考的是如何使用api,而不是如何记住。在拿到陌生的工具时,如何能快速上手呢。😸
bean.xml 配置文件
<!-- 配置要扫描的包-->
<context:component-scan base-package="com.jyu.spring.txhome"/>
<!-- 配置引入外部属性文件-->
<context:property-placeholder location="classpath:c3p0-config.properties"/>
<!-- 配置数据源-->
<bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
<property name="driverClass" value="${driverClass}"/>
<property name="jdbcUrl" value="${jdbcUrl}"/>
<property name="user" value="${user}"/>
<property name="password" value="${password}"/>
</bean>
<!-- 配置JDBCTemplate-->
<bean class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务管理器-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<constructor-arg name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置开启基于注解的事务管理功能-->
<tx:annotation-driven transaction-manager="transactionManager"/>
c3p0-config.properties
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/revj?rewriteBatchedStatements=true
user=root
password=ysk
acquireIncrement=5
initialPoolSize=10
minPoolSize=5
maxPoolSize=10
maxStatements=5
maxStatementsPerConnection=2
5.1 JDBCTemplate的常用方法
序号 | 作用 | 补充 | |
---|---|---|---|
1-1 | public T queryForObject(String sql, Class requiredType, Object… args) | 返回单行单列 | |
1-2 | public T queryForObject(String sql, RowMap rowMapper, Object… args) | 返回一行数据,封装到bean | RowMap是接口,常用实现类BeanPropertyRowMapperBeanPropertyRowMapper(Class<T> mappedClass) |
1-3 | public List query(String var1, RowMapper var2, Object… var3) | 返回多行数据,封装到List | |
2 | public int upata(String sql, Object… args) | 更新数据,返回受影响的行数 | |
3 | public int[] batchUpdate(String sql, List<Object[]> batchArgs) | 批量操作 |
返回单行单列
String sql = "SELECT name FROM monster WHERE id =100";
String name = bean.queryForObject(sql, String.class);
System.out.println(name);
返回单行
public void selectDataByJdbcTemplate() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");
//得到 JdbcTemplate bean
JdbcTemplate bean = ioc.getBean(JdbcTemplate.class);
String sql = "SELECT id as monsterId,name,skill FROM monster WHERE id =?";
//下面这个 rowmapper 是一个接口,可以将查询的结果,封装到你指定的 Monster 对象中.
RowMapper<Monster> rowMapper = new BeanPropertyRowMapper<Monster>(Monster.class);
Monster monster = bean.queryForObject(sql, rowMapper, 100);
System.out.println("monster= " + monster);
}
返回多行
String sql = "SELECT id as monsterId,name,skill FROM monster WHERE id >=?";
RowMapper<Monster> rowMapper = new BeanPropertyRowMapper<Monster>(Monster.class);
List<Monster> monster_list = bean.query(sql, rowMapper, 200);
更新
String sql = "UPDATE monster SET skill = ? WHERE id=?";
int affected = bean.update(sql, "美女计", 300);
System.out.println("affected= " + affected);
System.out.println("update data ok~");
批量操作
String sql = "INSERT INTO monster VALUES(?, ?, ?)";
List<Object[]> param_list = new ArrayList<Object[]>();
param_list.add(new Object[]{500, "白蛇精", "吃人"});
param_list.add(new Object[]{600, "青蛇精", "吃小孩"});
bean.batchUpdate(sql, param_list);
System.out.println("batch add ok")
5.2 【具名参数】NamedParamterJDBCTemplate
序号 | 作用 | 解析 | |
---|---|---|---|
1 | public int update(String sql, Map<String, ?> paramMap) | 更新数据,返回受影响的行数。根据paramMap填充sql | |
2 | public int update(String sql, SqlParameterSource paramSource) | 更新数据,返回受影响的行数。根据对象属性填充sql | SqlParameterSource是接口,常用的实现类为BeanPropertySqlParameterSource(Object object) |
ApplicationContext ioc =
new ClassPathXmlApplicationContext("JdbcTemplate_ioc.xml");
//得到 NamedParameterJdbcTemplate bean
NamedParameterJdbcTemplate namedParameterJdbcTemplate =
ioc.getBean(NamedParameterJdbcTemplate.class);
String sql = "INSERT INTO monster VALUES(:my_id, :name, :skill)";
Map<String, Object> map_parameter = new HashMap<String, Object>();
map_parameter.put("my_id", 800);
map_parameter.put("name", "螃蟹精");
map_parameter.put("skill", "钳子无敌大法");
namedParameterJdbcTemplate.update(sql, map_parameter);
NamedParameterJdbcTemplate namedParameterJdbcTemplate =
ioc.getBean(NamedParameterJdbcTemplate.class);
String sql = "INSERT INTO monster VALUES(:monsterId, :name, :skill)";
Monster monster = new Monster(900, "狐狸精", "狐媚之术");
SqlParameterSource source = new BeanPropertySqlParameterSource(monster);
namedParameterJdbcTemplate.update(sql, source);
6 声明式事务
声明式事务:该事务是建立在AOP之上的,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或加入一个事务,在执行完目标方法之后根据执行情况提交或回滚事务。
事务传播机制
REQUIRED | 如果有事务在运行,当前方法就在这个事务内运行,否则就启动一个新事务,并在自己的事务内运行。 |
REQUIRES_NEW | 当前方法必须启动事务,并在自己的事务内运行,如果有事务正在运行,就应该将其挂起。 |
SUPPORTS | 如果有事务在运行,当前方法就在这个事务内运行,否则它可以不运行在事务中 |
NOT_SUPPORTED | 当前方法不应在事务中运行,如果有事务正在运行,将它挂起 |
MANDATORY | 当前方法必须运行在事务中运行,如果没有事务正在运行,就抛出异常 |
NEVER | 当前方法不应该运行在事务中运行,如果有事务正在运行,就抛出异常 |
NESTED | 如果有事务在运行,当前方法就应该在这个事务嵌套的事务内运行,否则就启动一个新事务,并在自己的事务内运行。 |
@Transtional(propagation=Propagation.REQUIRED, isolation=Isolation.REPLEATED_READER, timeout=2)
基础配置参考mysql基础的事务隔离机制。
timeout 表示超时回滚
如果一个事务执行的时间超过某个时间限制,就让该事务回滚
propagation表示事务传播机制
isolation表示事务隔离级别
MySQL的快忆
猜你准来看
补一点笔记中用到的MySQL知识点,希望能帮到大家快速的回忆、最短时间上手应用。
增删改查
单表的简单操作,恭喜sql入门( ̄﹃ ̄)
select
select (columnName_1,columnName_2)
from tableName
where 条件表达式
group by 分组列
having 分组后的过滤条件
order by 分组列名1,分组列名2 DESC /*默认升序,desc 升序*/
limit start,rowNum /* 从start行开始,一共rowNum行*/
insert
insert into tableName(列名1,列名2)
values(行1列值1,行1列值2),
(行2列值1,行2列值2)
delete
delete from tableName
where 条件
update
update tableName
set columnName1 = 值
where 条件
MySQL事务
事务用于保证数据的一致性,它是一组相关的dml语句组成的,该组的dml语句要么全部成功,要么全部失败。
start transaction /* 开启一个事务 */
savepoint 保存点名 /* 设置保存点 */
rollback to 保存点 /* 回退事务 */
rollback /* 回退全部事务 */
commit /*提交事务,所有操作生效,不可回退*/
MySQL只有在InnoDB引擎下才支持使用事务,MyISAM擎不支持事务。不开启事务的默认情况下dml语句是自动提交的不能回滚 。set autocommit=off
后默认不再自动提交。
事务隔离机制
多个连接开启各自事务,操作数据库中数据时,数据库系统负责隔离操作,保证各个连接获取数据的准确性。
——韩顺平循序渐进学java
定义 | 纯白话巧记 | |
---|---|---|
脏读(dirty read) | 一个事务读取到另一个事务未提交的改变。 | 读取到未提交的数据 |
不可重复读 (norepeatable read) | 一个事务中多次进行查询,由于其他已提交 的事务进行修改或删除,使其每次查询返回结果集不同。 | 前后多次读取,数据内容不一致 |
幻读 (phantom read) | 一个事务中多次进行查询,由于其他已提交 的事务进行插入,使其每次查询返回结果集不同。 | 前后多次读取,数据总量不一致 |
这篇文章推荐给第一次接触事务的同学,该文中主要列举了有关脏读、不可重复读、幻读的相关案例,能帮助新手更好的理解,值得一读。
【数据库】快速理解脏读、不可重复读、幻读_SunAlwaysOnline的博客-CSDN博客
隔离级别 | 脏读 | 不可重复读 | 幻读 | 加锁读 |
---|---|---|---|---|
读未提交(Read uncommitted) | ✔️ | ✔️ | ✔️ | 不加锁 |
读已提交(Read committed) | ❌ | ✔️ | ✔️ | 不加锁 |
可重复读(Repeatable read) | ❌ | ❌ | ✔️ | 不加锁 |
可串行化(Serializable) | ❌ | ❌ | ❌ | 加锁 |
SQL92 标准,mysql数据库改进,InnoDB引擎,很大程度不可重复读隔离级别解决了的幻读问题,但是在没有彻底解决。
推荐文章:美团三面:一直追问我, MySQL 幻读被彻底解决了吗?