使用前面所学的基础知识来构建一个属于自己的持久层框架,将会涉及到的一些知识点:工厂模式
- Factory 工厂模式
- 构造者模式(Builder 模式)
- 代理模式
- 反射
- 自定义注解,注解的反射,xml 解析,
- 数据库元数据,元数据的反射等
image.png
根据代理Dao实现CRUD操作(XML方式实现)
1、查询操作
UserDao中添加接口
User findById(Integer userId);
<select id="findById" resultType="com.it.pojo.User" parameterType="int">
select * from user where id = #{uid}
</select>
注: resultType:返回结果集的类型
parameterType:用于指定传入参数的类型
sql 语句中使用#{} 字符 :
它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。具体的数据是由#{}里面的内容决定的。
{} 中内容的写法:
由于数据类型是基本类型,所以此处可以随意写。
#{} 中内容的写法:
由于数据类型是基本类型,所以此处可以随意写。
2、测试
public class MybatisTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession sqlSession;
private UserDao userDao;
@Test
public void test(){
User user =userDao.findById(41);
System.out.println(user);
}
@Before
public void init() throws Exception{
//1.读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory的构建对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.使用创建工厂对象
factory = builder.build(in);
//4.创建sqlsession
sqlSession = factory.openSession();
//5.使用sqlsession创建dao接口代理的对象
userDao = sqlSession.getMapper(UserDao.class);
}
@After
public void destroy() throws Exception{
sqlSession.commit();
sqlSession.close();
in.close();
}
}
2、保存操作
int saveUser(User user);
<insert id="saveUser" parameterType="com.it.pojo.User" >
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
注意:parameterType 属性:代表参数的类型,因为我们要传入的是一个类的对象,所以类型就写类的全名称。
sql 语句中使用#{}字符:它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。具体的数据是由#{}里面的内容决定的。
#{}中内容的写法:由于我们保存方法的参数是 一个 User 对象,此处要写 User 对象中的属性名称。
#{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user.而直接写 username。
它用的是 ognl 表达式。ognl 表达式:
它是 apache 提供的一种表达式语言,全称是:
Object Graphic Navigation Language 对象图导航语言
它是按照一定的语法格式来获取数据的。
语法格式就是使用 #{对象.对象}的方式
@Test
public void testSave(){
User user = new User();
user.setUsername("nihao");
user.setAddress("上海");
user.setSex("男");
user.setBirthday(new Date());
System.out.println(user);
userDao.saveUser(user); //插入
System.out.println(user);
}
如果没有提交事务,结果是不会写入到mysql数据库中的
@After
public void destroy() throws Exception{
sqlSession.commit();
sqlSession.close();
in.close();
}
如何获取新增用户 id 的返回值
<insert id="saveUser" parameterType="com.it.pojo.User" >
<!-- 配置保存时获取插入的 id -->
<selectKey keyColumn="id" keyProperty="id" resultType="int">
select last_insert_id();
</selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
返回结果会封装到user的pojo对象中,事务的回滚也会消耗id
image.png
3、更新操作
int updateUser(User user);
<!-- 更新用户 -->
<update id="updateUser" parameterType="com.it.pojo.User">
update user set username=#{username},birthday=#{birthday},sex=#{sex},
address=#{address} where id=#{id}
</update>
@Test
public void testUpdate(){
User user = userDao.findById(52);
//更新
user.setAddress("美国");
int res = userDao.updateUser(user);
System.out.println(res);
}
此时的res返回为1,操作了一条数据
4、删除操作
int deleteUser(Integer userId);
<delete id="deleteUser" parameterType="int">
delete from user where id = #{uid}
</delete>
@Test
public void testDelte(){
int i = userDao.deleteUser(52);
System.out.println(i);
User user = userDao.findById(52);
System.out.println(user);
}
5、用户模糊查询
List<User> findByName (String username);
<select id="findByName" parameterType="String" resultType="com.it.pojo.User" >
select * from user where username like #{username}
</select>
@Test
public void testFindByName(){
List<User> list = userDao.findByName("%王%");
for (User user:list){
System.out.println(user);
}
}
image.png
在输入查询参数的时候,使用了%
配置文件中的#{username}也只是一个占位符, SQL 语句显示为“?”。
模糊查询的另外一种配置
<select id="findByName" parameterType="String" resultType="com.it.pojo.User" >
select * from user where username like '%${value}%'
</select>
我们在上面将原来的#{}占位符,改成了 ${value}。注意如果用模糊查询的这种写法,那么${value}的写法就是固定的,不能写成其它名字。在他的外面再加上%模糊匹配符合
image.png
可以发现,我们在程序代码中就不需要加入模糊查询的匹配符
%了,这两种方式的实现效果是一样的,但执行的语句是不一样的。
{}与${}的区别
#{} 表示一个占位符号
通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。
${} 表示拼接 sql 串
通过${}可以将 parameterType 传入的内容拼接在 sql中且不进行 jdbc 类型转换,${}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value。
模糊查询的${value}源码分析
image.png
这就说明了源码中指定了读取的 key 的名字就是”value”,所以我们在绑定参数时就只能叫 value 的名字
了。
5、用户聚合查询
统计用户数量
int findTotal();
<select id="findTotal" resultType="int">
select count(*) from user;
</select>
@Test
public void testFindTotal(){
int total = userDao.findTotal();
System.out.println(total);
}
mybatis 与 JDBC 比较
1.数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:
在 SqlMapConfig.xml 中配置数据链接池,使用连接池管理数据库链接。
2.Sql 语句写在代码中造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java 代码。
解决:
将 Sql 语句配置在 XXXXmapper.xml 文件中与 java 代码分离。
3.向sql语句传参数麻烦,因为sql语句的where 条件不一定,可能多也可能少,占位符需要和参数对应。
解决:
Mybatis自动将 java 对象映射至 sql 语句,通过 statement 中parameterType 定义输入参数的类型。
4.对结果集解析麻烦,sql 变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成 pojo 对象解析比较方便。
解决:
Mybatis自动将 sql执行结果映射至 java 对象,通过 statement 中的 resultType 定义输出结果的类型。











网友评论