链接
概念:用JAVA操作关系型数据库的API
本质:JDBC是sun公司定义的接口/规则,实现类由数据库厂商实现,称为驱动。
好处:同一套代码操作不同的关系型数据库;可以随时替换底层数据库,访问数据库的Java代码基本不变。
下载jar包
在项目新建路径,放入jar包,add as library
代码
public class demo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
1.注册驱动 在mysql5之后的驱动jar包可以不写,在jar包中的meta-inf中services中的java.sql.Driver中记录
// Class.forName("com.mysql.cj.jdbc.Driver");
// Driver中有静态代码块,进行注册驱动
// static {
// try {
// DriverManager.registerDriver(new Driver());注册驱动
// } catch (SQLException var1) {
// throw new RuntimeException("Can't register driver!");
// }
// }
// 2.获取连接 如果是本机的3306可以简写url="jdbc:mysql:///jdbcdemo?useSSL=false&serverTimezone=UTC";
String url="jdbc:mysql://127.0.0.1:3306/jdbcdemo?useSSL=false&serverTimezone=UTC";
String usr="root";
String pwd="000000";
Connection connection= DriverManager.getConnection(url,usr,pwd);
// 3.定义sql
String sql="update user set pwd ='2' where user='1'";
// 4.获取执行sql的对象的statement
Statement statement=connection.createStatement();
// 5.执行sql,返回受影响的行数
int count=statement.executeUpdate(sql);
// 6.释放资源
statement.close();
connection.close();
}
}
1.注册驱动 registerDriver
2.获取数据库连接 getConnection
1.获取执行SQL的对象
createStatement 普通执行
prepareStatement 防止sql注入
CallableStatement prepareCall 执行存储过程的对象
获取的CallableStatement
执行对象是用来执行存储过程的,而存储过程在mysql中不常用。
2.管理事务
MySQL事务管理
开启事务:BEGIN;/START TRANSACTION
提交事务:COMMIT;
回滚事务:ROLLBACK;
mysql默认自动提交事务
JDBC事务管理:Connection接口中定义了三个对应的方法
开启事务:setAutoCommit(boolean autoCommit):true为自动提交事务;false为手动提交事务,即为开启事务。
提交事务:commit();
回滚事务:rollback();
public static void main(String[] args) throws ClassNotFoundException, SQLException {
1.注册驱动 在mysql5之后的驱动jar包可以不写,在jar包中的meta-inf中services中的java.sql.Driver中记录
// Class.forName("com.mysql.cj.jdbc.Driver");
// Driver中有静态代码块,进行注册驱动
// static {
// try {
// DriverManager.registerDriver(new Driver());注册驱动
// } catch (SQLException var1) {
// throw new RuntimeException("Can't register driver!");
// }
// }
// 2.获取连接 如果是本机的3306可以简写url="jdbc:mysql:///jdbcdemo?useSSL=false&serverTimezone=UTC";
String url="jdbc:mysql://127.0.0.1:3306/jdbcdemo?useSSL=false&serverTimezone=UTC";
String usr="root";
String pwd="000000";
Connection connection= DriverManager.getConnection(url,usr,pwd);
// 3.定义sql
String sql1="update user set pwd ='3' where user='1'";
String sql2="update user set pwd ='3' where user='2'";
// 4.获取执行sql的对象的statement
Statement statement=connection.createStatement();
try {
connection.setAutoCommit(false);
int count1=statement.executeUpdate(sql1);
System.out.println(count1);
int i=3/0;
int count2=statement.executeUpdate(sql2);
System.out.println(count2);
// 提交
connection.commit();
}catch (Exception e){
connection.rollback();
// 出现异常回滚
e.printStackTrace();
}
// 6.释放资源
statement.close();
connection.close();
}
执行sql语句
int executeUpdate(sql) 执行DML,DDL语句(DML操作数据,DDL操作表结构)
返回值:DML为影响的行数,DDL执行成功也可能返回0
ResultSet executeQuery 执行DQL语句
返回值:Result结果集对象
boolean next(): 1.将光标从当前位置向下移动一行 2.判断当前行是否为有效行
xxx getXXX(参数);
参数:int 列的编号,从1开始。String 列的名称。
public static void main(String[] args) throws ClassNotFoundException, SQLException {
1.注册驱动 在mysql5之后的驱动jar包可以不写,在jar包中的meta-inf中services中的java.sql.Driver中记录
// Class.forName("com.mysql.cj.jdbc.Driver");
// Driver中有静态代码块,进行注册驱动
// static {
// try {
// DriverManager.registerDriver(new Driver());注册驱动
// } catch (SQLException var1) {
// throw new RuntimeException("Can't register driver!");
// }
// }
// 2.获取连接 如果是本机的3306可以简写url="jdbc:mysql:///jdbcdemo?useSSL=false&serverTimezone=UTC";
String url="jdbc:mysql://127.0.0.1:3306/jdbcdemo?useSSL=false&serverTimezone=UTC";
String usr="root";
String pwd="000000";
Connection connection= DriverManager.getConnection(url,usr,pwd);
// 3.定义sql
String sql1="select * from user";
// 4.获取执行sql的对象的statement
Statement statement=connection.createStatement();
ResultSet rs= statement.executeQuery(sql1);
while (rs.next()){
// int user=rs.getInt(1);
// String password=rs.getString(1);
int user=rs.getInt("user");
String password=rs.getString("pwd");
System.out.println("id="+user+" pwd="+password);
}
// 6.释放资源
rs.close();
statement.close();
connection.close();
}
继承Statement
预编译sql,性能更高
预防SQL注入:将敏感字符进行转义
public static void main(String[] args) throws ClassNotFoundException, SQLException {
1.注册驱动 在mysql5之后的驱动jar包可以不写,在jar包中的meta-inf中services中的java.sql.Driver中记录
// Class.forName("com.mysql.cj.jdbc.Driver");
// Driver中有静态代码块,进行注册驱动
// static {
// try {
// DriverManager.registerDriver(new Driver());注册驱动
// } catch (SQLException var1) {
// throw new RuntimeException("Can't register driver!");
// }
// }
// 2.获取连接 如果是本机的3306可以简写url="jdbc:mysql:///jdbcdemo?useSSL=false&serverTimezone=UTC";
String url="jdbc:mysql://127.0.0.1:3306/jdbcdemo?useSSL=false&serverTimezone=UTC&useServerPrepStmts=true";
String usr="root";
String pwd="000000";
Connection connection= DriverManager.getConnection(url,usr,pwd);
// 3.定义sql
String sql="update user set pwd =? where user='1'";
// 4.获取PreparedStatement对象 此时已经进行了预编译
PreparedStatement statement=connection.prepareStatement(sql);
// 5.设置?的值
statement.setString(1,"2");
// 执行sql
int count=statement.executeUpdate();
System.out.println(count);
// 6.释放资源
statement.close();
connection.close();
}
开启预编译 在建立连接的url后面加上&useServerPrepStmts=true
配置mysql执行日志
在mysql配置文件(my.ini)中添加如下配置 (需要重启)
log-output=FILE
general-log=1
general_log_file=“D:\mysql.log”
slow-query-log=1
slow_query_log_file=“D:\mysql_slow.log”
long_query_time=2
Java代码操作数据库流程:
将sql语句发送到MySQL服务器端
MySQL服务端会对sql语句进行如下操作
检查SQL语句
检查SQL语句的语法是否正确。
编译SQL语句。将SQL语句编译成可执行的函数。
检查SQL和编译SQL花费的时间比执行SQL的时间还要长。如果我们只是重新设置参数,那么检查SQL语句和编译SQL语句将不需要重复执行。这样就提高了性能。
执行SQL语句
开启预编译,第二次执行可以省略前面两步
简介
数据库连接池是个容器,负责分配连接。
允许应用重复使用一个现有的数据库连接,而不是再重新建立一个。
使用之后不成功释放资源称为连接泄露。
连接池是一开始就创建连接,使用从中取,使用完毕归还即可。
实现
SUN提供数据库连接池标准接口,由第三方实现
Connection getConnection();
不需要通过DriverManager获取connection对象,而是从连接池datasource获取connection对象。
常见的数据库连接池:DBCP,C3p0,Druid
Druid(德鲁伊)
druid.properties
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/jdbcdemo?useSSL=false&serverTimezone=UTC&useServerPrepStmts=true
username=root
password=000000
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
public static void main(String[] args) throws Exception {
// 1.导入jar包
// 2.定义配置文件
// 3.加载配置文件
Properties properties=new Properties();
properties.load(new FileInputStream("D:\\project2\\headfirst\\src\\main\\resources\\druid.properties"));
// 4.获取连接池对象
DataSource dataSource= DruidDataSourceFactory.createDataSource(properties);
// 5.获取数据库连接
Connection connection=dataSource.getConnection();
System.out.println(connection);
// System.out.println(System.getProperty("user.dir"));
}
管理和构建Java项目的工具
项目对象模型(Project Object Model)pom
依赖管理模型(Dependency)
插件(Plugin)
阿里云私服
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
compile :编译 生成target
clean:清理 清除target
package:打包 生成jar包
install:打包 并安装到仓库
Maven 坐标主要组成
dependency中的scope属性,不设置默认为compile
依赖范围 | 编译classpath | 测试classpath | 运行classpath | 例子 |
---|---|---|---|---|
compile | Y | Y | Y | logback |
test | - | Y | - | Junit |
provided | Y | Y | - | servlet-api |
runtime | - | Y | Y | jdbc驱动 |
system | Y | Y | - | 存储在本地的jar包 |
官网
持久层框架,用来简化JDBC开发
Mybatis是apache的一个开源项目ibatis,2010年这个项目由apache software foundation迁移到了google code 并且改名为Mybatis,2013年11月迁移到了Github。
持久层
JDBC缺点:
1.硬编码 :注册驱动,获取连接;sql语句;
2.操作繁琐:手动设置参数;手动封装结果集;
1.编写核心配置文件
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false&serverTimezone=UTC&useServerPrepStmts=true"/>
<property name="username" value="root"/>
<property name="password" value="000000"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="UserMapper.xml"/>
mappers>
configuration>
2.编写sql映射文件
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<select id="selectAll" resultType="com.ln.pojo.User">
select * from tb_user
select>
mapper>
3.编写代码
public static void main(String[] args) throws IOException {
// 1.添加mybatis的核心配置文件,获取sqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2.获取sqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
// 3.执行sql
List<User> users=sqlSession.selectList("test.selectAll");
System.out.println(users);
// 4.释放资源
sqlSession.close();
}
1.定义同名mapper接口,将接口和sql映射文件放在同一目录下
2.设置名称空间为接口的全类名
3.在接口定义方法,方法名就是sql映射文件中的id,并保持参数类型和返回值一致。
public static void main(String[] args) throws IOException {
// 1.添加mybatis的核心配置文件,获取sqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2.获取sqlSession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
// 3.执行sql
// List users=sqlSession.selectList("test.selectAll");
// 3.1 获取UserMapper接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectAll();
System.out.println(users);
// 4.释放资源
sqlSession.close();
}
配置文件
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false&serverTimezone=UTC&useServerPrepStmts=true"/>
<property name="username" value="root"/>
<property name="password" value="000000"/>
dataSource>
environment>
environments>
<mappers>
<package name="com.ln.mapper"/>
mappers>
configuration>
环境配置
在核心配置文件的 environments
标签中其实是可以配置多个 environment
,使用 id
给每段环境起名,在 environments
中使用 default='环境id'
来指定使用哪儿段配置。我们一般就配置一个 environment
即可。
别名
<typeAliases>
<package name="domain.blog"/>
typeAliases>
此时resulttype不需要带包名了。
配置需要遵循官网的顺序。
在idea中安装mybatisX来协助开发。
Mybatis完成操作需要几步?
1.编写接口方法
2.编写SQL
3.执行方法
数据库字段名和实体类字段名称不一致,无法自动封装。
1.起别名
缺点:每次查询都要定义别名,可以用sql片段解决
sql片段
<sql id="brand_column">
id, brand_name as brandName, company_name as companyName, ordered, description, status
sql>
<select id="selectAll" resultType="brand">
select
<include refid="brand_column" />
from tb_brand;
select>
缺点:不灵活
2.resultMap
<resultMap id="brandResultMap" type="com.ln.mybatis.pojo.Brand">
<result column="brand_name" property="brandName">result>
<result column="company_name" property="companyName">result>
resultMap>
<select id="selectAll" resultMap="brandResultMap">
select * from tb_brand;
select>
参数占位符
1.#{}: 会将其替换为 ?,为了防止sql注入
2.${}: 拼sql。会存在sql注入的问题
3.使用时机:
参数传递时使用 #{}
表名或者列名不固定的情况下使用 ${}
parameterType
用来设置参数类型,可以省略
<select id="selectById" parameterType="int" resultMap="brandResultMap">
select *
from tb_brand where id = ${id};
select>
特殊字符处理
1.转义字符 <
就是 <
的转义字符
2.CDATA区
多条件查询
1.@Param(“sql中参数占位符的名称”)
2.实体类对象 sql参数名和实体属性名对应
3.Map集合 sql参数名和map中的key对应
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName,@Param("brandName") String brandName);
List<Brand> selectByCondition(Brand brand);
List<Brand> selectByCondition(Map map);
@Test
public void testSelectByCondition() throws IOException {
int staues=1;
String companyName="%华为%";
String brandName="%华为%";
Brand brand=new Brand();
brand.setStatus(1);
brand.setCompanyName("%华为%");
brand.setBrandName("%华为%");
Map map = new HashMap();
map.put("status" , staues);
map.put("companyName", companyName);
map.put("brandName" , brandName);
// 1、获取sqlsessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2.获取sqlsession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取Mapper接口的代理对象 crtl alt v 快速声明对象
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 4.执行方法
List<Brand> brands=mapper.selectByCondition(staues,companyName,brandName);
System.out.println("结果为"+brands);
List<Brand> brands2=mapper.selectByCondition(brand);
System.out.println("结果为"+brands2);
List<Brand> brands3=mapper.selectByCondition(map);
System.out.println("结果为"+brands3);
// 5.释放资源
sqlSession.close();
}
多条件
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
<where>
<if test="status != null">
and status = #{status}
if>
<if test="companyName != null and companyName != '' ">
and company_name like #{companyName}
if>
<if test="brandName != null and brandName != '' ">
and brand_name like #{brandName}
if>
where>
select>
and 必须要加,mybatis会帮你删掉第一个and,但是不会帮你多加
单条件
/**
* 单条件动态查询
* @param brand
* @return
*/
List<Brand> selectByConditionSingle(Brand brand);
<select id="selectByConditionSingle" resultMap="brandResultMap">
select *
from tb_brand
<where>
<choose>
<when test="status != null">
status = #{status}
when>
<when test="companyName != null and companyName != '' ">
company_name like #{companyName}
when>
<when test="brandName != null and brandName != ''">
brand_name like #{brandName}
when>
choose>
where>
select>
mybatis事务
openSession(); 默认开启事务,需要sqlSession.commit();
openSession(true); 可以设置为自动提交事务(关闭事务)
/**
* 添加
*/
void add(Brand brand);
<insert id="add">
insert into tb_brand (brand_name, company_name, ordered, description, status)
values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
insert>
返回添加数据的主键
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into tb_brand (brand_name, company_name, ordered, description, status)
values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
insert>
/**
* 修改
*/
void update(Brand brand);
<update id="update">
update tb_brand
<set>
<if test="brandName != null and brandName != ''">
brand_name = #{brandName},
if>
<if test="companyName != null and companyName != ''">
company_name = #{companyName},
if>
<if test="ordered != null">
ordered = #{ordered},
if>
<if test="description != null and description != ''">
description = #{description},
if>
<if test="status != null">
status = #{status}
if>
set>
where id = #{id};
update>
单个
/**
* 根据id删除
*/
void deleteById(int id);
<delete id="deleteById">
delete from tb_brand where id = #{id};
delete>
批量
/**
* 批量删除
*/
void deleteByIds(int[] ids);
<delete id="deleteByIds">
delete from tb_brand where id
in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
foreach>
;
delete>
collection 属性:
void deleteByIds(@Param("ids") int[] ids);
Mybatis 接口方法中可以接收各种各样的参数,如下:
MyBatis提供了 ParamNameResolver类来进行参数封装
会将值进行两次放置 一次k为arg0,一次为param0。
使用@param会替换arg0
单个参数
POJO 类型
直接使用。要求 属性名
和 参数占位符名称
一致
Map 集合类型
直接使用。要求 map集合的键名
和 参数占位符名称
一致
Collection 集合类型
Mybatis 会将集合封装到 map 集合中,如下:
map.put(“arg0”,collection集合);
map.put(“collection”,collection集合;
可以使用 @Param
注解替换map集合中默认的 arg 键名。
List 集合类型
Mybatis 会将集合封装到 map 集合中,如下:
map.put(“arg0”,list集合);
map.put(“collection”,list集合);
map.put(“list”,list集合);
可以使用 @Param
注解替换map集合中默认的 arg 键名。
Array 类型
Mybatis 会将集合封装到 map 集合中,如下:
map.put(“arg0”,数组);
map.put(“array”,数组);
可以使用 @Param
注解替换map集合中默认的 arg 键名。
其他类型
比如int类型,参数占位符名称
叫什么都可以。尽量做到见名知意
注解用于简单语句
@Select(value = "select * from tb_user where id = #{id}")
public User select(int id);