ORM
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xxs7ZE2Q-1671874123591)(笔记.assets/1665191124835.png)]
ORM:对象关系映射。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AgSQJ3bi-1671874123592)(笔记.assets/1665191531727.png)]
问题:我们之前使用JDBC是否是面向对象的操作?
保存数据:把数据从对象中逐个取出,填入sql语句对应的位置。执行sql。
读取数据:从sql查询的结果集中取出数据,设置到对象对应的位置。
如果程序本身已经知道列名和对象属性名之间的对应关系,程序是否可以自己完成JDBC的基本操作?
于是就有了各种ORM框架…
- Hibernate 强大的ORM框架。全自动化框架。
- MyBatis 最流行的ORM框架。半自动化框架。
- 其他…
MyBatis框架
Helloworld
官方网站:https://mybatis.net.cn/
[1]在项目中添加MyBatis的依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
不要忘记JDBC的依赖。
[2]添加对应的配置文件,构建对应的SqlSessionFactory对象。
2.1在项目的main/resources下添加配置文件:mybatis-config.xml
(文件名可以随意,但是不要太随意)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://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.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/crm?serverTimezone=GMT%2B8&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root123"/>
</dataSource>
</environment>
</environments>
</configuration>
这个配置文件很明显是配置连接数据库的相关属性。
2.2准备实体类和数据表
create table user(
id bigint not null primary key auto_increment,
username varchar(200),
userage int,
usertel char(11)
)
/**
* @author 戴着假发的程序员
* @company 起点编程
* 2022/10/8 9:31
*/
public class User {
private Long id;
private String username;
private int userage;
private String usertel;
}
tisp: 这里确保类的属性名和数据表的列名完全一致。
2.3 在main/resources/maps下添加配置文件: UserMapping.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 相当于当前文件的唯一标志 -->
<mapper namespace="com.qidian.UserMapping">
<!-- 这里是查询的sql语句的配置 -->
<select id="selectUser" resultType="com.qidian.pojo.User">
select * from user where id = #{id}
</select>
</mapper>
在mybatis-config.xml中添加配置:
<!-- 注册映射文件 -->
<mappers>
<mapper resource="maps/UserMapping.xml"/>
</mappers>
2.4 在测试类中创建SqlSessionFactory对象
对于MyBatis来说,和数据库的一次链接就是一个会话。于是在MyBatis中就有一个SqlSession的概念。
SqlSession就相当于之前的一个Connection对象。
我们要得到SqlSession对象,就需要SqlSessionFactory。
/**
* @author 戴着假发的程序员
* @company 起点编程
* 2022/10/8 9:39
*/
public class MyBatisTest {
@Test
public void testGetSqlSessionFactory() throws IOException {
// 主配置文件的位置
String resource = "mybatis-config.xml";
// 通过MyBatis提供的Resources类获取一个输入流指向主配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建SqlSessionFactoryBuilder,通过SqlSessionFactoryBuilder对象创建一个SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
System.out.println(sqlSessionFactory);
}
}
[3]获取SqlSession,执行sql语句
可以通过SqlSessionFactory获取一个sqlSession
@Test
public void testHelloword() throws IOException {
// 主配置文件的位置
String resource = "mybatis-config.xml";
// 通过MyBatis提供的Resources类获取一个输入流指向主配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建SqlSessionFactoryBuilder,通过SqlSessionFactoryBuilder对象创建一个SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
System.out.println(sqlSessionFactory);
// 获取一个SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 通过sqlsession执行sql语句
Object user = sqlSession.selectOne("com.qidian.UserMapping.selectUser", 2);
User u = (User) user;
System.out.println(u);
}
执行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9SjqDzLR-1671874123592)(笔记.assets/1665193620813.png)]
我们不需要在创建connection,Statement,获取数据放入对象等等操作。
MyBatis可以执行sql语句,并且直接返回对象。
程序的说明:
配置文件mybatis-config.xml 主要用来配置MyBatis的基本配置,比如数据库连接的相关信息,这个配置配置文件主要用来生成SqlSessionFactory。
配置文件UserMapping.xml为User实体类和user数据表之间的映射文件,主要用来配置要执行的sql语句。这个配置文件要注册到mybatis-config.xml文件中。
通过SqlSessionFactory获取一个SqlSession,通过SqlSession就可以执行配置在映射文件中的sql语句。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YnKS3NsI-1671874123593)(笔记.assets/1665194669477.png)]
执行sql语句的时候,需要指明sql,sql的标志是 映射文件的namspace+sql语句的id。
执行sql语句之后MyBatis会根据sql语句中设置的resultType封装一个对象,并且将数据放入对象中。
MyBatis的CRUD
MyBatis是将sql语句和java程序分离的。
sql语句是配置在映射文件中的。自动完成参数设置和结果集封装。
提供的SqlSession对象有大量可以使用的API用来执行JDBC的基本操作。
[1]通过id查询用户
在映射文件中配置sql:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z5XDlT6J-1671874123593)(笔记.assets/1665194964198.png)]
在一个映射文件中可以配置多个sql语句,查询语句的标签是
select
每一个sql语句都应该有id,这个id应该在当前的映射文件中唯一标志当前的sql语句。
查询语句都是有resultType或者resultMap的配置,主要用来配置查询结果的返回值类型。
sql语句中可以使用#{xxx}来做占位符。当一个sql语句只有一个参数的时候,#{这里的可以随意}
[2]添加用户操作
准备sql语句:在UserMapping中添加sql配置:
<!-- 添加用户 -->
<insert id="saveUser" parameterType="com.qidian.pojo.User">
insert into user(username,usertel,userage) values(#{username},#{usertel},#{userage})
</insert>
添加的sql语句要使用
insert
标签,没有resultType配置,但是要配置属性parameterTyep,我们这里配置的是实体类的全限定类名。sql语句中的参数要写实体对象的属性名。 #{属性名}
测试程序:
准备一个Before方便测试:
private SqlSessionFactory sqlSessionFactory = null;
@Before // 在单元测试之前执行
public void before() throws IOException {
// 主配置文件的位置
String resource = "mybatis-config.xml";
// 通过MyBatis提供的Resources类获取一个输入流指向主配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建SqlSessionFactoryBuilder,通过SqlSessionFactoryBuilder对象创建一个SqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
添加测试程序
@Test
public void testInsert(){
// 准备实体对象
User user = new User();
user.setUsername("鸣人");
user.setUserage(19);
user.setUsertel("13013013030");
// 获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 执行sql语句
int result = sqlSession.insert("com.qidian.UserMapping.saveUser", user);
// MyBatis不自动提交事务,增删改操作需要我们手动的提交事务
sqlSession.commit();
System.out.println(result);
}
[3]修改用户操作
添加sql语句:
<!-- 修改用户 -->
<update id="updateUser" parameterType="com.qidian.pojo.User">
update user set username=#{username},userage=#{userage},usertel=#{usertel}
where id=#{id}
</update>
测试程序:
@Test
public void testUpdate(){
// 获取一个SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 查询一个用户
User user = sqlSession.selectOne("com.qidian.UserMapping.selectUser", 2);
// 修改信息
user.setUsertel("12212212222");
// 保存修改的信息
int update = sqlSession.update("com.qidian.UserMapping.updateUser", user);
// 不要忘记提交事务
sqlSession.commit();
System.out.println(update);
}
[4]删除用户信息
添加sql:
<!-- 删除用户 -->
<delete id="deleteUser" parameterType="long">
delete from user where id = #{xxx}
</delete>
测试程序:
@Test
public void testDelete(){
// 获取一个SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 根据ID删除用户信息
int update = sqlSession.update("com.qidian.UserMapping.deleteUser", 4L);
// 不要忘记提交事务
sqlSession.commit();
System.out.println(update);
}
[5]查询全部
添加sql语句:
<!-- 查询全部 -->
<!-- 即便我们查询的而是list,这里的resultType要写list中的类型 -->
<select id="selectAll" resultType="com.qidian.pojo.User">
select * from user
</select>
测试程序:
@Test
public void testSelectAll(){
// 获取一个SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 查询全部的操作
List<User> list = sqlSession.selectList("com.qidian.UserMapping.selectAll");
System.out.println(list);
}
列名和属性名不一致的情况
MyBatis自动完成了映射关系:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hMSZ8wBg-1671874123594)(笔记.assets/1665196334060.png)]
因为我们这里的列名和属性名完全一致,所以可以自动映射。
如果不一致可能会出现问题。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lbL6H8Km-1671874123594)(笔记.assets/1665196476148.png)]
添加映射文件:SourceMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 相当于当前文件的唯一标志 -->
<mapper namespace="com.qidian.SourceMapper">
<!-- 查询全部 -->
<!-- 即便我们查询的而是list,这里的resultType要写list中的类型 -->
<select id="selectAll" resultType="com.qidian.pojo.Source">
select * from source
</select>
</mapper>
将映射文件注册到mybaits-config.xml中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lcvIUKn6-1671874123595)(笔记.assets/1665196579411.png)]
测试程序:
@Test
public void testSelectAllSource(){
SqlSession sqlSession = sqlSessionFactory.openSession();
List<Object> list = sqlSession.selectList("com.qidian.SourceMapping.selectAll");
System.out.println(list);
}
结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7erOZ0Rk-1671874123595)(笔记.assets/1665196687929.png)]
由于MyBatis认为属性sourceName在数据表source中没有对应的列,所以就不设置任何值。
解决方案1:给查询结果的列名设置别名。
修改sql:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w1ltqd1d-1671874123596)(笔记.assets/1665196794740.png)]
解决方案2:配置一个resultMap,将查询结果的返回值类型设置为对应的resultMap
在映射文件中添加resultMap
<!-- 添加一个结果映射关系 (配置数据表的列和实体类属性之间的对应关系)-->
<resultMap id="baseResultMap" type="com.qidian.pojo.Source">
<!-- 配置主键映射 一定要配置列名和属性名,类型是可以自动识别的-->
<id column="id" property="id" javaType="java.lang.Integer"/>
<!-- 其他属性配置 -->
<result column="source_name" property="sourceName"/>
<result column="created" property="created"/>
<result column="updated" property="updated"/>
<result column="status" property="status"/>
</resultMap>
修改sql配置,不能在配置resultType了,要配置resultMap。(这两个属性是互斥的)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AT9DxVlP-1671874123597)(笔记.assets/1665197228041.png)]
测试!
映射文件的配置
sql片段
我们可以在映射文件中设置一个sql片段,在其他的sql语句中引用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gUdD7tKq-1671874123597)(笔记.assets/1665198525987.png)]
select语句的属性配置
属性 | 描述 |
---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType | 将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
parameterMap | 用于引用外部 parameterMap 的属性,目前已被废弃。请使用行内参数映射和 parameterType 属性。 |
resultType | 期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。 |
resultMap | 对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。 |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。 |
useCache | 将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。 |
fetchSize | 这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)。 |
statementType | 可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
resultSetType | FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)。 |
databaseId | 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。 |
resultOrdered | 这个设置仅针对嵌套结果 select 语句:如果为 true,将会假设包含了嵌套结果集或是分组,当返回一个主结果行时,就不会产生对前面结果集的引用。 这就使得在获取嵌套结果集的时候不至于内存不够用。默认值:false 。 |
resultSets | 这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。 |
- parameterType 配置参数类型,参数类型可以是简单类型(基本类型和String),也可以是集合类型,也可以是实体类类型。
在MyBatis中内置了一部分类型,而且每个类型都有对应的别名:
下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。
别名 | 映射的类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
- resultType预期的返回值类型
可以是任何内置的类型或者我们自定义的pojo。如果返回的是list,一定要配置list的泛型类型。
resultType和resultMap是互斥的属性,不能同时配置。
- resultMap 配置结果映射
大部分情况下我们都会有结果映射配置。在前面的案例中我们用resultMap解决了列名和属性名不一致的情况。
insert, update 和 delete配置
insert、update和delete是没有resultType或者resultMap的配置的,默认返回值类型都是int类型的。
可以配置parameterType。也没有缓存相关的配置,只有刷新缓存的配置。
在insert语句中有个特殊的配置。
属性 | 描述 |
---|---|
useGeneratedKeys | (仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。 |
keyProperty | (仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset )。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
keyColumn | (仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
之前遇到问题:当一个数据表的主键是自增列的时候,我们添加一条数据进去之后希望可以得到刚刚生成的id。这时我们的做法是在同一个事务中立刻查询。
MyBatis可以通过上面的设置解决这个问题。
当我们配置了useGeneratedKeys为true的时候,MyBatis会将自增列的结果直接回填到对象中。
案例:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iUIrjENB-1671874123597)(笔记.assets/1665199381763.png)]
测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yN1grYtj-1671874123598)(笔记.assets/1665199495467.png)]
除过上面的解决方案之外,还有一个解决方案。
问题:有的时候,我们的主键不是自增列,也不是手动设置的而是从其他数据表获取的。MyBatis就提供了解决方案。(我们这里还是使用自增列演示)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3knfDbIu-1671874123598)(笔记.assets/1665199754505.png)]
sql语句的参数设置
[1]关于#和$
#{xxx} 如果只有一个参数,xxx可以随意。
看问题:通过名称模糊查询用户
sql:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VIVmUC14-1671874123598)(笔记.assets/1665199981228.png)]
不用测试:这个sql肯定不行,因为MyBatis会将#{username}
直接作为字符串处理。
解决方案1:
修改sql:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sYA0YbIe-1671874123599)(笔记.assets/1665200144386.png)]
测试程序:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Lmp2qW48-1671874123599)(笔记.assets/1665200164685.png)]
解决方案2:我们可以使用${}
修改sql:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s7bYj3sh-1671874123600)(笔记.assets/1665200220400.png)]
tips: 当使用${}接收参数的时候,如果参数只有一个简单类型的值,则这里引用的参数的名字必须是固定字符串value
如果是pojo或者map 则要写对应的key或者属性名。
测试程序:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RR2L9p3X-1671874123600)(笔记.assets/1665200291520.png)]
#
使用使用占位符的方式设置sql中的参数的。
$
是使用字符串连接的方式将参数设置到sql中的。
[2]简单类型
我们这里说的简单类型是只基本类型和String
简单类型如果是单个参数 #{随意} ${value } 直接可以接收。
[3] pojo类型
添加和修改操作往往传递的参数都是pojo类型。这时在sql中获取数据的时候要注意:
#{对象的属性名}
同理 ${对象的属性名}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EMHXJZ6S-1671874123600)(笔记.assets/1665200658022.png)]
[4] 参数是map类型的
如果参数类型是map类型,我们可以使用#{key}获取对应的值。
我们实现添加source的方法:使用map作为参数。
在SourceMapping.xml 中添加sql:
<!-- 添加source,使用map作为参数 -->
<insert id="saveSource" parameterType="map">
insert into source(source_name,created,updated,status)
values (#{sName},#{created},#{updated},#{status})
</insert>
测试:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9xbvwfZX-1671874123600)(笔记.assets/1665200982441.png)]
返回值类型
[1]一行一列的简单类型
查询总条数
sql语句:
<!-- 查询总条数 -->
<select id="count" resultType="int">
select count(*) from user
</select>
测试程序:
@Test
public void testCount(){
// 获取一个SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
Integer o = sqlSession.selectOne("com.qidian.UserMapping.count");
System.out.println(o);
}
[2]返回一个pojo对象
<!-- 这里是查询的sql语句的配置 -->
<select id="selectUser" resultType="com.qidian.pojo.User">
select * from user where id = #{id}
</select>
[3]返回一个列表
tips:resultType要写list中的泛型类型
<!-- 通过名称模糊查询用户 -->
<select id="selectUserByUsername" resultType="com.qidian.pojo.User">
select * from user where username like #{username}
</select>
[4]返回一个map
需求:查询一个source,返回类型为map
sql:
<select id="queryByIdForMap" parameterType="long" resultType="map">
select * from source where id = #{id}
</select>
测试程序:
@Test
public void testSelectForMap(){
// 获取一个SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
Map map = sqlSession.selectOne("com.qidian.SourceMapping.queryByIdForMap", 2L);
System.out.println(map);
}
[5]返回值类型是list,其中的泛型是map
查询所有的source,
<select id="selectAllForMap" resultType="map">
select * from source
</select>
测试程序:
@Test
public void testSelectAllForMap(){
// 获取一个SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
List<Map> map = sqlSession.selectList("com.qidian.SourceMapping.selectAllForMap");
System.out.println(map);
}
DAO的开发:传统方式
有如下的接口:
/**
* @author 戴着假发的程序员
* @company 起点编程
* 2022/10/8 14:36
*/
public interface SourceDAO {
int save(Source source);
List<Source> queryAll();
Source queryById(Long id);
}
实现类:
我们可以将获取sqlSessionFactory的过程设置为公共的。不需要每次都获取。
/**
* @author 戴着假发的程序员
* @company 起点编程
* 2022/10/8 14:39
*/
public class SourceDAOImpl implements SourceDAO {
// 这一部分的内容可以写在BaseDAO中的
private static SqlSessionFactory sqlSessionFactory = null;
static{
// 主配置文件的位置
String resource = "mybatis-config.xml";
// 通过MyBatis提供的Resources类获取一个输入流指向主配置文件
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
// 创建SqlSessionFactoryBuilder,通过SqlSessionFactoryBuilder对象创建一个SqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//-----------------------------
public int save(Source source) {
int result = -1;
SqlSession sqlSession = sqlSessionFactory.openSession();
result = sqlSession.insert("com.qidian.SourceMapping.save",source);
sqlSession.commit();
return result;
}
@Override
public List<Source> queryAll() {
return sqlSessionFactory.openSession().selectList("com.qidian.SourceMapping.selectAll");
}
@Override
public Source queryById(Long id) {
return (Source) sqlSessionFactory.openSession().selectOne("com.qidian.SourceMapping.selectById",id);
}
}
对应的mapper文件中的sql语句:
<!-- 添加source,使用map作为参数 -->
<insert id="save" parameterType="map">
insert into source(source_name,created,updated,status)
values (#{sourceName},#{created},#{updated},#{status})
</insert>
<select id="selectById" parameterType="long" resultType="com.qidian.pojo.Source">
select * from source where id = #{id}
</select>
<select id="selectAll" resultMap="baseResultMap">
select <include refid="allColumns"/> from source
</select>
DAO开发:代理mapper方式
要开发的接口:
tips这里的接口是mapper不再是DAO了。
/**
* @author 戴着假发的程序员
* @company 起点编程
* 2022/10/8 14:49
*/
public interface UserMapper {
int save(User user);
User queryById(Long id);
List<User> queryByName(String name);
List<User> queryAll();
int count();
}
在resources/maps下添加一个配置文件: UserMapper.xml
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eQ9h6XLK-1671874123601)(笔记.assets/1665211991819.png)]
tips:mapper文件中的namespace必须写UserMapper接口的全限定类名。
在mapper中添加sql语句,添加的要求
①UserMapper接口中的每一个方法都必须对应的写一条sql语句。
②Sql语句的id必须和UserMapper接口中对应的方法的名字一致。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 相当于当前文件的唯一标志 -->
<!-- 这里的namespace必须写对应的接口的全限定类名 -->
<mapper namespace="com.qidian.dao.UserMapper">
<!-- 这里的id必须和方法名对应 -->
<insert id="save" parameterType="com.qidian.pojo.User">
insert into user(username,usertel,userage)
values(#{username},#{usertel},#{userage})
</insert>
<!-- 根据id查询 -->
<select id="queryById" parameterType="long" resultType="com.qidian.pojo.User">
select * from user where id = #{id}
</select>
<!-- 根据名称模糊查询 -->
<select id="queryByName" parameterType="string" resultType="com.qidian.pojo.User">
select * from user where username like '%${value}%'
</select>
<!-- 查询全部 -->
<select id="queryAll" resultType="com.qidian.pojo.User">
select * from user
</select>
<!-- 查询总条数 -->
<select id="count" resultType="int">
select count(*) from user
</select>
</mapper>
【1】接口中的每一个方法都必须在mapper文件中有对应的sql。
【2】mapper文件中的sql语句可以多。
【3】接口中不能有重载的方法。
我们使用代理mapper实现CRUD。(我们不写实现类)
测试:
/**
* @author 戴着假发的程序员
* @company 起点编程
* 2022/10/8 15:00
*/
public class ProxyMapperTest {
private SqlSessionFactory sqlSessionFactory = null;
@Before // 在单元测试之前执行
public void before() throws IOException {
// 主配置文件的位置
String resource = "mybatis-config.xml";
// 通过MyBatis提供的Resources类获取一个输入流指向主配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建SqlSessionFactoryBuilder,通过SqlSessionFactoryBuilder对象创建一个SqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testSave(){
User user = new User();
user.setUsertel("15815815826");
user.setUserage(18);
user.setUsername("如花");
// 调用Mapper进行保存
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int save = userMapper.save(user);
sqlSession.commit();
System.out.println(save);
}
@Test
public void testQuery(){
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取一个动态代理产生的mapper对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 调用方法
System.out.println(userMapper.count());
System.out.println(userMapper.queryById(1L));
System.out.println(userMapper.queryAll());
System.out.println(userMapper.queryByName("卡"));
}
}
@Test
public void testSave(){
User user = new User();
user.setUsertel(“15815815826”);
user.setUserage(18);
user.setUsername(“如花”);
// 调用Mapper进行保存
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int save = userMapper.save(user);
sqlSession.commit();
System.out.println(save);
}
@Test
public void testQuery(){
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取一个动态代理产生的mapper对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 调用方法
System.out.println(userMapper.count());
System.out.println(userMapper.queryById(1L));
System.out.println(userMapper.queryAll());
System.out.println(userMapper.queryByName("卡"));
}
}
作品转自@戴着假发的程序员