MyBatis-Day2
第1章 回顾mybatis的自定义再分析和环境搭建
自定义开发流程图
回顾mybatis环境搭建步骤
第一步:创建 maven 工程
新建普通java工程day02_mybatis,在下面新建maven模块day02_eesy_01mybatisCRUD
第二步:导入坐标
出的问题,写dependency无提示信息,报红是点击右侧提示选update就有了。然后还是写了以后红波浪,就clean和reimport刷新解决,没有改VM先让它找本地对应有的,明明本地有为啥不自动去找!!
dependency用了log4j日志工具要把log4j.properties放到res下
第三步:编写必要代码(实体类和持久层接口)
User.java 和 IUserDao接口
第四步:编写 SqlMapConfig.xml
需要拷贝一下头部信息粘贴
第五步:编写映射配置文件IUseDao.xml
也需要拷贝一下头部信息粘贴
<!--id映射查询所有方法 resultType="com.xxw.domain.User"写把结果类型-->
<select id="findAll" resultType="com.xxw.domain.User">
select * from user;
</select>
第六步:编写测试类 MybatisTest
使用了@Test替代昨天的main方法(就方法名上@Test无需main了直接写就是,每个@Test可以直接运行)
/**
* 测试查询所有方法(用代理类生成IUserDao接口的的代理对象)
*/
@Test
public void testFindAll() throws Exception {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//builder生成工厂
SqlSession sqlSession = factory.openSession();//工厂生产sqlSession对象
IUserDao userDao = sqlSession.getMapper(IUserDao.class);//session获取接口的代理类
List<User> users = userDao.findAll();
for(User user:users){
System.out.println(user);
}
sqlSession.close();
in.close();
}
运行查找所有数据输出成功,昨天的环境又重新搭建成功
第2章 基于代理 Dao 实现 CRUD 操作
就还是使用上面那个maven模块day02_eesy_01mybatisCRUD
开始在中增加对数据库增删改查的方法
先写一个增加用户保存到数据库的方法,对应的IUserDao接口类增加saveUser抽象方法
/**
* 保存用户 插入一条数据
* @param user
*/
void saveUser(User user);
对应的IUserDao.xml增加匹配方法的sql语句
<!-- 映射保存用户方法 参数类型就是插入数据的类型。插入是一条实体类的数据#号{}号 里面写每一个插入数据实体类对象的属性-->
<insert id="saveUser" parameterType="com.xxw.domain.User">
insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});
</insert>
然后在测试类MybatisTest用@Test注解测试saveUser方法
由于又要重复获取IUserDao接口代理类的代码操作和释放资源操作(和testFindAll时一样),所以把这两部分代码封装一下并借助@before和@after实现每一个@test之前之后都执行这两部分代码。
public class MybatisTest { private InputStream in; private SqlSession sqlSession; private IUserDao userDao; @Before//用于在测试方法执行之前执行(把那些重复的构建工厂获取代理的代码放到@before里面) public void init()throws Exception{ //1.读取配置文件,生成字节输入流 in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.获取SqlSessionFactory SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in); //3.获取SqlSession对象 sqlSession = factory.openSession(); //4.获取dao的代理对象 userDao = sqlSession.getMapper(IUserDao.class); } @After//用于在测试方法执行之后执行(重复的释放资源操作) public void destroy()throws Exception{ //提交事务!不然sava没有提交就会自动回滚 sqlSession.commit(); //6.释放资源 sqlSession.close(); in.close(); } /** * 测试查询所有 */ @Test public void testFindAll(){ //5.执行查询所有方法 List<User> users = userDao.findAll(); for(User user : users){ System.out.println(user); } } /** * 测试保存操作 */ @Test public void testSave(){//特别注意:执行方法后要进行提交事务的操作。 User user = new User(); user.setUserName("modify User property"); user.setUserAddress("北京市顺义区"); user.setUserSex("男"); user.setUserBirthday(new Date()); //5.执行保存方法 userDao.saveUser(user); } }
运行结果:表格后面插入了一条49号数据,id是自增的
更新某条用户数据方法
IUserDao.xml
<!--也是和插入一样传入了参数所以要写参数类型-->
<update id="updateUser" parameterType="com.xxw.domain.User">
update user set username=#{userName},address=#{userAddress},sex=#{userAex},birthday=#{userBirthday} where id=#{userId}
</update>
测试类MybatisTest
@Test
public void testUpdate(){
User user = new User();
user.setUserId(49);
user.setUserName("xxw user");
user.setUserAddress("北京市海淀区");
user.setUserSex("女");
user.setUserBirthday(new Date());
//5.执行更新方法
userDao.updateUser(user);
}
运行结果:49号被重新更新数据了(保存插入只能在最末尾,更新可以任意id更新
根据id删除某条数据
IUserDao接口
/**
* 根据Id删除用户
* @param userId
*/
void deleteUser(Integer userId);
IUserDao.xml
<!--根据id删除用户 sql语句中id的#{}里面只是一个占位符,传啥都行反正参数只有一个啥都是该参数-->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{uid}
</delete>
测试类MybatisTest
/**
* 测试删除操作
*/
@Test
public void testDelete(){
//5.执行删除方法
userDao.deleteUser(43);
}
运行结果:43号数据被删除
根据id查询用户数据
IUserDao.xml
<!--根据id查询用户有传入参数,也有返回值 都要写清楚类型-->
<select id="findById" parameterType="INT" resultType="com.xxw.domain.User">
select * from user where id = #{uid}
</select>
测试类MybatisTest
/**
* 测试根据id查询用户信息操作
*/
@Test
public void testFindOne(){
//5.执行查询一个方法
User user = userDao.findById(49);
System.out.println(user);
}
运行结果:49号数据查找成功
根据用户名模糊查询
IUserDao接口
/**
* 根据名称模糊查询用户信息
* @param username
* @return
*/
List<User> findByName(String username);
IUserDao.xml
<!--根据名称模糊查询 与id查询的区别是用like代替等号-->
<select id="findByName" parameterType="string" resultType="com.xxw.domain.User">
select * from user where username like #{name}
-- select * from user where username like '%${value}%' 这样写也可以
</select>
测试类MybatisTest
/**
* 测试模糊查询操作
*/
@Test
public void testFindByName(){
//5.执行查询一个方法
List<User> users = userDao.findByName("%王%");
// List<User> users = userDao.findByName("王"); 这样用对应上面那样写
for(User user : users){
System.out.println(user);
}
}
运行结果:成功把数据库中用户名中带王自的行数据查找出来
聚合函数
查询总用户数
IUserDao接口
/**
* 查询总用户数
* @return
*/
int findTotal();
IUserDao.xml
<select id="findTotal" resultType="int">
select count(id) from user;
</select>
测试类MybatisTest
/**
* 测试查询总记录条数
*/
@Test
public void testFindTotal(){
//5.执行查询一个方法
int count = userDao.findTotal();
System.out.println(count);
}
运行结果:6条
Mybatis的CRUD-保存操作的细节-获取保存数据的ID
sql:select last_insert_id();
IUserDao.xml
<!-- 映射保存用户方法 参数类型就是插入数据的类型。插入是一条实体类的数据#号{}号 里面写实体类对象的属性-->
<insert id="saveUser" parameterType="com.xxw.domain.User">
<!--增加配置插入操作后,获取插入数据的id-->
<selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});
</insert>
测试类MybatisTest
/**
* 测试保存操作
*/
@Test
public void testSave(){//特别注意:执行方法后要进行提交事务的操作。
User user = new User();
user.setUserName("modify User property");
user.setUserAddress("北京市顺义区");
user.setUserSex("男");
user.setUserBirthday(new Date());
System.out.println("保存操作之前:"+user);//保存前id是null!!!
//5.执行保存方法
userDao.saveUser(user);
System.out.println("保存操作之后:"+user);//运行结果:插入用户保存后有了该条保存的id!!!!
第3章 Mybatis 的参数深入
Mybatis使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo的属性名称。
(感觉有点像jsp里的el表达式直接写属性名取值...长得都类似...
听不太懂,求助同学的博客...
ParameterType可以传递:
1.简单类型,int,String等
2.pojo对象(即javabean)?所以pojo类就是实体类的意思!
使用ognl表达式解析对象字段的值。如:#{pojo属性名称}
OGNL表达式:object graphic navigation language,对象图导航语言。通过对象的取值方法来获取数据,在写法上把get省略了。如:user.username。
开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。 Pojo 类中包含 pojo。 需求:根据用户名查询用户信息,查询条件放到 QueryVo 的 user 属性中。 (多个查询条件用一个查询条件参数vo对象)
IUserDao接口
/**
* 根据queryVo中的条件查询用户
* @param vo
* @return
*/
List<User> findUserByVo(QueryVo vo);
}
3.pojo包装对象
1.main/java/domain中创建一个QueryVo类,定义一个user类的私有属性,并生成getters&setters:
public class QueryVo {//查询条件类 是包装User实体类而来
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
2.IUserDao.xml增加
<!-- 根据queryVo的条件查询用户 参数是一个查询条件类,是包装实体类而成,即把实体类做成属性-->
<select id="findUserByVo" parameterType="com.xxw.domain.QueryVo" resultType="com.xxw.domain.User">
select * from user where username like #{user.userName}
用途就是like这儿可以放表的其他属性?就是用什么属性查数据的时候只需要改这里不需要再去接口写方法?或者别的表别的属性也只需改这儿?个人理解
</select>
3.MybatisTest中写测试
/**
* 测试使用QueryVo作为查询条件
*/
@Test
public void testFindByVo(){
QueryVo vo = new QueryVo();
User user = new User();
user.setUserName("%王%");//百分号是为了模糊
vo.setUser(user);
//5.执行查询一个方法
List<User> users = userDao.findUserByVo(vo);
for(User u : users){
System.out.println(u);
}
}
}
运行结果:模糊查询出3条名字包含王的User类数据
第4章 Mybatis 的输出结果封装 (结果集的深入)
由于我的实体类属性名与数据库不匹配,只有userName属性和数据库username列由于window不区分大小写可以被查出来,其他三个属性查出来打印的值都是null...
User{userId=null, userName='老王', userAddress='null', userSex='null', userBirthday=null}
User{userId=null, userName='小二王', userAddress='null', userSex='null', userBirthday=null}
User{userId=null, userName='传智播客', userAddress='null', userSex='null', userBirthday=null}
User{userId=null, userName='老王', userAddress='null', userSex='null', userBirthday=null}
User{userId=null, userName='小马宝莉', userAddress='null', userSex='null', userBirthday=null}
User{userId=null, userName='xxw user', userAddress='null', userSex='null', userBirthday=null}
User{userId=null, userName='modify User property', userAddress='null', userSex='null', userBirthday=null}
但是增删改不影响,在数据库中操作不需要返回数据库中,实体类的属性和数据库列名不一样也可以。
如何解决查询find出的问题呢?
1.sql语句中对实体类属性取别名
比如在IUserDao.xml中改findAll的sql:select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user;
2.Mybatis提供一种在IUserDao.xml中配置查询结果的列名和实体类的属性吗的对应关系
<!--配置 查询结果的列名和实体类的属性名的对应关系 -->
<resultMap id="userMap" type="com.xxw.domain.User">
<!-- 主键字段的对应 -->
<id property="userId" column="id"></id>
<!--非主键字段的对应-->
<result property="userName" column="username"></result>
<result property="userAddress" column="address"></result>
<result property="userSex" column="sex"></result>
<result property="userBirthday" column="birthday"></result>
</resultMap>
然后resultType不要了改成resultMap
<!--id映射查询所有方法 resultType="com.xxw.domain.User"写把结果类型-->
<select id="findAll" resultMap="userMap">改这里!!
-- select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user;
select * from user;
</select>
其他查询操作也都只要改为resultMap="userMap"就可以,这对于查询操作较多的操作起来方便一些,但效率没有起别名只用改sql高。
(当然效率最高的还是是实体类类名与数据库列名写成一样的。。。
第5章 Mybatis 传统 DAO 层开发(编写dao的实现类)[了解]
之前学javaweb时用的都是写实现类。Dao一个接口一个实现类,Service层一个接口一个实现类。
第6章 SqlMapConfig.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> <!--这是mybatis的主配置文件--> <!--配置环境--> <environments default="mysql"> <!--配置mysql的环境--> <environment id="mysql"> <!--配置事务类型--> <transactionManager type="JDBC"></transactionManager> <!--配置数据源(连接池)--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/eesy"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </dataSource> </environment> </environments> <mappers> <!--xml配置映射文件--> <mapper resource="com/xxw/dao/IUserDao.xml"></mapper> </mappers> </configuration>
properties标签
加入<properties>就把配置连接数据库的基本信息的带<property> 标签的都复制到<properties>里面去,然后给原来的value用${}引用
用处就是可以把<properties>里面的带<property> 标签的内容放到外面放一个jdbcConfig.properties文件里。这个SqlMapConfig.xml里面就只剩<property>原来的value用${}引用就可以。
typeAliases标签 ---解释Integer的写法
<!--使用typeAliases配置别名,它只能配置domain中类的别名 -->
<typeAliases>
<!--typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名后IUserDao.xml就不再区分大小写 -->
<typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>
</typeAliases>
IUserDao.xml中的parameterType="com.xxw.domain.User"就可以=“user"其中user不分大小写
还可以直接改包
<!-- 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写-->
<package name="com.xxw.domain"></package> 替代<typeAlias>那个放在</typeAliases>里面
mappers标签的子标签:package
同理,这个mappers里的package
<mappers>
<!--xml配置映射文件-->
<!--<mapper resource="com/xxw/dao/IUserDao.xml"></mapper>-->
<!-- package标签是用于指定dao接口所在的包,当指定了之后就不需要在写mapper以及resource或者class了 -->
<package name="com.itheima.dao"></package>
</mappers>
但是弹幕说映射配置文件路径和名称一定要和java对上,不然报错;还有起别名容易导致日志乱码
添加上述三个标签后的SqlMapConfig.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> <!-- 配置properties 可以在标签内部配置连接数据库的信息。也可以通过属性引用外部配置文件信息 resource属性: 常用的,短一些。。。 用于指定配置文件的位置,是按照类路径的写法来写,并且必须存在于类路径下。 url属性: 是要求按照Url的写法来写地址 URL:Uniform Resource Locator 统一资源定位符。它是可以唯一标识一个资源的位置。 它的写法: http://localhost:8080/mybatisserver/demo1Servlet 协议 主机 端口 URI URI:Uniform Resource Identifier 统一资源标识符。它是在应用中可以唯一定位一个资源的。 --> <!--<properties url="file:///D:/IdeaProjects/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.properties">--> <properties resource="jdbcConfig.properties"> <!-- <property name="driver" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/eesy_mybatis"></property> <property name="username" value="root"></property> <property name="password" value="1234"></property>--> </properties> <!--使用typeAliases配置别名,它只能配置domain中类的别名 --> <typeAliases> <!--typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就再区分大小写 --> <!--<typeAlias type="com.xxw.domain.User" alias="user"></typeAlias>--> <!-- 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写--> <package name="com.itheima.domain"></package> </typeAliases> <!--这是mybatis的主配置文件--> <!--配置环境--> <environments default="mysql"> <!--配置mysql的环境--> <environment id="mysql"> <!--配置事务类型--> <transactionManager type="JDBC"></transactionManager> <!--配置数据源(连接池)--> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </dataSource> </environment> </environments> <mappers> <!--xml配置映射文件--> <!--<mapper resource="com/xxw/dao/IUserDao.xml"></mapper>--> <!-- package标签是用于指定dao接口所在的包,当指定了之后就不需要在写mapper以及resource或者class了 --> <package name="com.xxw.dao"></package> </mappers> </configuration>