目录
1、核心配置文件
▶ 官网上可以看配置
注意:配置各个标签需要遵循官网的配置顺序,否则会报错。
▶ 环境配置
2、配置别名
1、查询操作
▶ 查询所有数据
▷ 书写步骤
编写接口方法:Mapper接口
* 参数:无,(查询所有数据功能是不需要根据任何条件进行查询的,所以此方法不需要参数)。
* 结果:List<Brand> ,(我们会将查询出来的每一条数据封装成一个 `Brand` 对象,而多条数据封装多个 `Brand` 对象,需要将这些对象封装到List集合中返回)。
* 编写SQL语句:SQL映射文件
* 执行方法、测试
▷ 编写接口
在 `com.itheima.mapper` 包写创建名为 `BrandMapper` 的接口。并在该接口中定义 `List<Brand> selectAll()` 方法。自己写的时候注意接口的位置写到什么地方。
public interface BrandMapper { List<Brand> selectAll(); }▷ 编写SQL语句
在 `reources` 下创建 `com/itheima/mapper` 目录结构,并在该目录下创建名为 `BrandMapper.xml` 的映射配置文件。自己写的时候找到对应的SQL书写映射文件。
<mapper namespace="com.itheima.mapper.BrandMapper"> <select id="selectAll" resultType="brand"> select * from tb_brand; </select> </mapper>▷ 测试方法
在 `MybatisTest` 类中编写测试查询所有的方法,在测试类中进行测试。
public void testSelectAll() throws IOException { //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接口的代理对象 BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); //4. 执行方法 List<Brand> brands = brandMapper.selectAll(); System.out.println(brands); //5. 释放资源 sqlSession.close(); }▷ 执行结果
存在的问题:从上面结果可以看到 `brandName` 和 `companyName` 这两个属性的数据没有封装成功,查询 实体类 和 表中的字段 发现,在实体类中属性名是 `brandName` 和 `companyName` ,而表中的字段名为 `brand_name` 和 `company_name`,那么我们只需要保持这两部分的名称一致这个问题就迎刃而解。
▷ 解决方式
数据库表的字段名称 和 实体类的属性名称 不一样,则不能自动封装数据: ①起别名:对不一样的列名起别名,让别名和实体类的属性名一样。缺点:每次查询都要定义一次别名<select id="selectAll" resultType="brand"> select id, brand_name as brandName, company_name as companyName, ordered, description, status from tb_brand; </select>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>②resultMap: 1. 定义<resultMap>标签 2. 在<select>标签中,使用resultMap属性替换 resultType属性<!-- id:唯一标识,type:映射的类型,支持别名 --> <resultMap id="brandResultMap" type="brand"> <result column="brand_name" property="brandName"/> <result column="company_name" property="companyName"/> </resultMap> <select id="selectAll" resultMap="brandResultMap"> select * from tb_brand; </select>id:完成主键字段的映射
column:表的列名
property:实体类的属性名
result:完成一般字段的映射
column:表的列名
property:实体类的属性名
▶ 查询详情
▷ 编写步骤
编写接口方法:Mapper接口
* 参数:id
查看详情就是查询某一行数据,所以需要根据id进行查询。而id以后是由页面传递过来。
* 结果:Brand
根据id查询出来的数据只要一条,而将一条数据封装成一个Brand对象即可
* 编写SQL语句:SQL映射文件
* 执行方法、进行测试
▷ 编写接口
Brand selectById(int id);▷ 编写SQL语句
<select id="selectById" resultMap="brandResultMap"> select * from tb_brand where id = #{id}; </select>▷ 测试方法
public void testSelectById() throws IOException { //接收参数 int id = 1; //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接口的代理对象 BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); //4. 执行方法 Brand brand = brandMapper.selectById(id); System.out.println(brand); //5. 释放资源 sqlSession.close(); }▷ 参数占位符
1. #{}: 会将其替换为 ?,为了防止SQL注入
2. ${}:拼sql。会存在SQL注入问题
3. 使用时机:
* 参数传递的时候:#{}
* 表名或者列名不固定的情况下:${} 会存在SQL注入问题4.参数类型:parameterType:可以省略
5.特殊字符处理:(比如:< )
* 转义字符:<* CDATA区 : <![CDATA[ < ]]>
▶ 多条件查询
▷ 书写步骤
1、编写接口方法
* 参数:所有查询条件
* 结果:List<Brand>
2、在映射配置文件中编写SQL语句3、编写测试方法并执行
▷ 编写接口
①使用 `@Param("参数名称")` 标记每一个参数,在映射配置文件中就需要使用 `#{参数名称}` 进行占位
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName, @Param("brandName") String brandName);②将多个参数封装成一个 实体对象 ,将该实体对象作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 `#{内容}` 时,里面的内容必须和实体类属性名保持一致。
List<Brand> selectByCondition(Brand brand);③将多个参数封装到map集合中,将map集合作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 `#{内容}` 时,里面的内容必须和map集合中键的名称一致。
List<Brand> selectByCondition(Map map);▷ 编写SQL语句
<select id="selectByCondition" resultMap="brandResultMap"> select * from tb_brand where status = #{status} and company_name like #{companyName} and brand_name like #{brandName} </select>▷ 进行测试
public void testSelectByCondition() throws IOException { //接收参数 int status = 1; String companyName = "华为"; String brandName = "华为"; // 处理参数 companyName = "%" + companyName + "%"; 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接口的代理对象 BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); //4. 执行方法 List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName); System.out.println(brands); //5. 释放资源 sqlSession.close();//封装对象 Brand brand = new Brand(); brand.setStatus(status); brand.setCompanyName(companyName); brand.setBrandName(brandName); //4.执行方法 List<Brand> brands = brandMapper.selectByCondition(brand);Map map = new HashMap(); map.put("status" , status); map.put("companyName", companyName); map.put("brandName" , brandName); //4.执行方法 List<Brand> brands = brandMapper.selectByCondition(map);▷ 动态SQL
① if 标签:条件判断,其中test 属性:逻辑表达式。
<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> </select>② where 标签,作用:* 替换where关键字,* 会动态的去掉关键字 ,* 如果所有的参数没有值则不加where关键字
<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>▶ 单个条件的动态SQL
▷ 编写接口
List<Brand> selectByConditionSingle(Brand brand);▷ 编写SQL
<select id="selectByConditionSingle" resultMap="brandResultMap"> select * from tb_brand <where> <choose><!--相当于switch--> <when test="status != null"><!--相当于case--> status = #{status} </when> <when test="companyName != null and companyName != '' "><!--相当于case--> company_name like #{companyName} </when> <when test="brandName != null and brandName != ''"><!--相当于case--> brand_name like #{brandName} </when> </choose> </where> </select>▷ 测试方法
public void testSelectByConditionSingle() throws IOException { //接收参数 int status = 1; String companyName = "华为"; String brandName = "华为"; // 处理参数 companyName = "%" + companyName + "%"; brandName = "%" + brandName + "%"; //封装对象 Brand brand = new Brand(); brand.setCompanyName(companyName); //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接口的代理对象 BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); //4. 执行方法 List<Brand> brands = brandMapper.selectByConditionSingle(brand); System.out.println(brands); //5. 释放资源 sqlSession.close(); }
2、添加操作
▶ 编写接口
void add(Brand brand);▶ 编写SQL
<insert id="add"> insert into tb_brand (brand_name, company_name, ordered, description, status) values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status}); </insert>▶ 测试方法
public void testAdd() throws IOException { //接收参数 int status = 1; String companyName = "波导手机"; String brandName = "波导"; String description = "手机中的战斗机"; int ordered = 100; //封装对象 Brand brand = new Brand(); brand.setStatus(status); brand.setCompanyName(companyName); brand.setBrandName(brandName); brand.setDescription(description); brand.setOrdered(ordered); //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接口的代理对象 BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); //4. 执行方法 brandMapper.add(brand); //提交事务 sqlSession.commit(); //5. 释放资源 sqlSession.close(); }▶ 主键返回
在数据添加成功后,有时候需要获取插入数据库数据的主键(主键是自增长)。比如:
* 添加订单数据
* 添加订单项数据,订单项中需要设置所属订单的id
▷ 更改SQL
<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>▷ 在 insert 标签上添加如下属性:
* useGeneratedKeys:是够获取自动增长的主键值。true表示获取
* keyProperty :指定将获取到的主键值封装到哪儿个属性里
3、修改操作
▶ 编写接口
void update(Brand brand);▶ 编写SQL
<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>▶ 测试方法
public void testUpdate() throws IOException { //接收参数 int status = 0; int id = 6; //封装对象 Brand brand = new Brand(); brand.setStatus(status); brand.setId(id); //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接口的代理对象 BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); //4. 执行方法 int count = brandMapper.update(brand); System.out.println(count); //提交事务 sqlSession.commit(); //5. 释放资源 sqlSession.close(); }
4、删除操作
▶ 单行删除
▷ 编写接口
void deleteById(int id);▷ 编写SQL
<delete id="deleteById"> delete from tb_brand where id = #{id}; </delete>▷ 测试方法
public void testDeleteById() throws IOException { //接收参数 int id = 6; //1. 获取SqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //2. 获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //SqlSession sqlSession = sqlSessionFactory.openSession(true); //3. 获取Mapper接口的代理对象 BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); //4. 执行方法 brandMapper.deleteById(id); //提交事务 sqlSession.commit(); //5. 释放资源 sqlSession.close(); }▶ 批删除除
▷ 编写接口
void deleteByIds(int[] ids);▷ 编写SQL:foreach 标签
用来迭代任何可迭代的对象(如数组,集合):
①collection 属性:
* mybatis会将数组参数,封装为一个Map集合。
* 默认:array = 数组
* 使用@Param注解改变map集合的默认key的名称
②item 属性:本次迭代获取到的元素。
③separator 属性:集合项迭代之间的分隔符。`foreach` 标签不会错误地添加多余的分隔符。也就是最后一次迭代不会加分隔符。
④open 属性:该属性值是在拼接SQL语句之前拼接的语句,只会拼接一次
⑤close 属性:该属性值是在拼接SQL语句拼接后拼接的语句,只会拼接一次<delete id="deleteByIds"> delete from tb_brand where id in <foreach collection="array" item="id" separator="," open="(" close=")"> #{id} </foreach> ; </delete>▷ 测试方法
public void testDeleteByIds() throws IOException { //接收参数 int[] ids = {5,7,8}; //1. 获取SqlSessionFactory String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //2. 获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //SqlSession sqlSession = sqlSessionFactory.openSession(true); //3. 获取Mapper接口的代理对象 BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); //4. 执行方法 brandMapper.deleteByIds(ids); //提交事务 sqlSession.commit(); //5. 释放资源 sqlSession.close(); }
5、MyBatis参数传递
▶ 多个参数
我们在接口方法中定义多个参数,Mybatis 会将这些参数封装成 Map 集合对象,值就是参数值,而键在没有使用 `@Param` 注解时有以下命名规则:
▷ 以 arg 开头 :第一个参数就叫 arg0,第二个参数就叫 arg1,以此类推。如:
> map.put("arg0",参数值1);
> map.put("arg1",参数值2);▷ 以 param 开头 : 第一个参数就叫 param1,第二个参数就叫 param2,依次类推。如:
> map.put("param1",参数值1);
> map.put("param2",参数值2);
① 验证一:
接口:
User select(String username,String password);SQL:
<select id="select" resultType="user"> select * from tb_user where username=#{arg0} and password=#{arg1} </select>或
<select id="select" resultType="user"> select * from tb_user where username=#{param1} and password=#{param2} </select>结果:
② 验证二:
将接口更改:
User select(@Param("username") String username, String password);则会看到下列运行结果
结论:以后接口参数是多个时,在每个参数上都使用 `@Param` 注解。这样代码的可读性更高。
▶ 单个参数
▷ 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);▷ 注意
注解是用来替换映射配置文件方式配置的,所以使用了注解,就不需要再映射配置文件中书写对应的 `statement`。
▷ Mybatis 针对 CURD 操作都提供了对应的注解。如下:
查询 :@Select
添加 :@Insert
修改 :@Update
删除 :@Delete▷ 注解实现方式
在接口中直接这样写:
@Select(value = "select * from tb_user where id = #{id}") public User select(int id);而编写SQL语句的那个配置文件就不需要在写SQL语句了。
▷ 注解完成简单功能,配置文件完成复杂功能。
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A
我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只