JDBC入门
1.JDBC(Java DataBase Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库。
2.JDBC原理
最终得出的结论是,由SUN提供一套访问数据库的规范(就是一组接口),并提供连接数据库的协议标准,然后各个数据库厂商会遵循SUN的规范提供一套访问自己公司的数据库服务器的API出现。SUN提供的规范命名为JDBC,而各个厂商提供的,遵循了JDBC规范的,可以访问自己数据库的API被称之为驱动!
3.JDBC核心类(接口)介绍
JDBC中的核心类有:DriverManager、Connection、Statement,和ResultSet
DriverManager(驱动管理器)的作用有两个:
注册驱动:这可以让JDBC知道要使用的是哪个驱动;
获取Connection:如果可以获取到Connection,那么说明已经与数据库连接上了。
Connection对象表示连接,与数据库的通讯都是通过这个对象展开的:
Connection最为重要的一个方法就是用来获取Statement对象;
Statement是用来向数据库发送SQL语句的
voidexecuteUpdate(String sql):执行更新操作(insert、update、delete等);
ResultSetexecuteQuery(String sql):执行查询操作,数据库在执行查询后会把查询结果,查询结果就是ResultSet;
ResultSet对象表示查询结果集,只有在执行查询操作后才会有结果集的产生
booleannext():使“行光标”移动到下一行,并返回移动后的行是否存在
XXXgetXXX(int col):众多get方法,获取当前行指定列上的值,参数就是列数,列数从1开始,而不是0。
4.JDBC入门操作
A:导jar包:驱动!
B:加载驱动类:Class.forName(“类名”);
C:给出ur、username、password,其中url背下来!
D:使用DriverManager类来得到Connection对象!
4.1:mysql数据库的驱动jar包:mysql-connector-java-5.1.13-bin.jar
4.2:获取连接
获取连接需要两步:
一是使用DriverManager来注册驱动
:注册驱动:
就只有一句话:Class.forName(“com.mysql.jdbc.Driver”)
原理:源码中静态代码块中会把com.mysql.jdbc.Driver注册到DriverManager
DriverManager.registerDriver(newcom.mysql.jdbc.Driver());
虽然可以注册驱动,属硬编码,依赖jar包,换数据库需要改代码
二是使用DriverManager来获取Connection对象。
:获取连接:
也只有一句代码:DriverManager.getConnection(url,username,password)
username和password为数据库用户名和密码
url:用来找到要连接数据库“网址”
mysql的url:jdbc:mysql://localhost:3306/mydb1
例:
Connectioncon =DriverManager.getConnection(“jdbc:mysql://localhost:3306/mydb1”,”root”,”123”);
4.3:获取Statement
Statementstmt = con.createStatement();
Statement是用来向数据库发送要执行的SQL语句的!
4.4 发送SQL增、删、改语句
Stringsql = “insert into user value(’zhangSan’, ’123’)”;
执行更新操作,即执行insert、update、delete,create table、alter table,drop table
intm = stmt.executeUpdate(sql);//m为影响的行数
4.5 发送SQL查询语句
Stringsql = “select * from user”;
ResultSetrs = stmt.executeQuery(sql);
executeQuery()方法返回的是ResultSet,ResultSet封装了查询结果,称之为结果集。
4.6 读取结果集中的数据
rs.next();//光标移动到第一行
rs.getInt(1);//获取第一行第一列的数据
常用方法:
ObjectgetObject(int col)
StringgetString(int col)
intgetInt(int col)
doublegetDouble(int col)
滚动结果集光标方法
voidbeforeFirst():把光标放到第一行的前面,这也是光标默认的位置;
voidafterLast():把光标放到最后一行的后面;
booleanfirst():把光标放到第一行的位置上,返回值表示调控光标是否成功;
booleanlast():把光标放到最后一行的位置上;
booleanisBeforeFirst():当前光标位置是否在第一行前面;
booleanisAfterLast():当前光标位置是否在最后一行的后面;
booleanisFirst():当前光标位置是否在第一行上;
booleanisLast():当前光标位置是否在最后一行上;
booleanprevious():把光标向上挪一行;
booleannext():把光标向下挪一行;
booleanrelative(int row):相对位移,当row为正数时,表示向下移动row行,为负数时表示向上移动row行;
booleanabsolute(int row):绝对位移,把光标移动到指定的行上;
intgetRow():返回当前光标所有行。
获取结果集元数据
得到元数据:rs.getMetaData(),
返回值为ResultSetMetaData;
获取结果集列数:int getColumnCount()
获取指定列的列名:String getColumnName(intcolIndex)
4.7 关闭资源
与IO流一样,关闭的顺序是先得到的后关闭,后得到的先关闭。
rs.close();
stmt.close();
con.close();
4.8 代码
public class Demo2 { /* * 连接数据库,得到Connection就算成功! * 对数据库做增、删、改 */ @Test public void fun1() throws ClassNotFoundException, SQLException { /* * 一、得到Connection * 1. 准备四大参数 * 2. 加载驱动类 * 3. 得到Connection */ // 准备四大参数 String driverClassName = "com.mysql.jdbc.Driver"; // jdbc协议的格式!jdbc:工商的名称:子协议(由工商自己来规定) // 对mysql而言,它的子协议结构://主机:端口号/数据库名称 String url = "jdbc:mysql://localhost:3306/mydb3"; String username = "root"; String password = "123"; // 加载驱动类 Class.forName(driverClassName); // 使用DriverManager,以及省下的3个参数,得到Connection Connection con = DriverManager.getConnection(url, username, password); /* * 二、对数据库做增、删、改 * 1. 通过Connection对象创建Statement * > Statement语句的发送器,它的功能就是向数据库发送sql语句! * 2. 调用它的int executeUpdate(String sql),它可以发送DML、DDL */ // 1. 通过Connection得到Statement对象 Statement stmt = con.createStatement(); // 2. 使用Statement发送sql语句! // String sql = "INSERT INTO stu VALUES('ITCAST_0003', 'wangWu', 88, 'male')"; // String sql = "UPDATE stu SET name='zhaoLiu', age=22, " + // "gender='female' WHERE number='ITCAST_0003'"; String sql = "DELETE FROM stu"; int r = stmt.executeUpdate(sql); System.out.println(r); } /** * 执行查询 * @throws ClassNotFoundException * @throws SQLException */ @Test public void fun2() throws ClassNotFoundException, SQLException { /* * 一、得到Connection * 二、得到Statement,发送select语句 * 三、对查询返回的“表格”进行解析! */ /* * 一、得到连接 * 1. 准备四大连接参数 */ String driverClassName = "com.mysql.jdbc.Driver"; String url = "jdbc:mysql://localhost:3306/exam"; String username = "root"; String password = "123"; /* * 2. 加载驱动类 */ Class.forName(driverClassName); /* * 3. 通过省下的三个参数调用DriverManger的getConnection(),得到连接 */ Connection con = DriverManager.getConnection(url, username, password); /* * 二、得到Statement,执行select语句 * 1. 得到Statement对象:Connection的createStatement()方法 */ Statement stmt = con.createStatement(); /* * 2. 调用Statement的ResultSet rs = executeQuery(String querySql) */ ResultSet rs = stmt.executeQuery("select * from emp"); /* * 三、解析ResultSet * 1. 把行光标移动到第一行,可以调用next()方法完成! */ while(rs.next()) {//把光标向下移动一行,并判断下一行是否存在! int empno = rs.getInt(1);//通过列编号来获取该列的值! String ename = rs.getString("ename");//通过列名称来获取该列的值 double sal = rs.getDouble("sal"); System.out.println(empno + ", " + ename + ", " + sal); } /* * 四、关闭资源 * 倒关 */ rs.close(); stmt.close(); con.close();//这个东东,必须要关,不关就死! }
4.9规范化代码
// 规范化 @Test public void fun3() throws Exception { Connection con = null;//定义引用 Statement stmt = null; ResultSet rs = null; try { /* * 一、得到连接 */ String driverClassName = "com.mysql.jdbc.Driver"; String url = "jdbc:mysql://localhost:3306/exam"; String username = "root"; String password = "123"; Class.forName(driverClassName); con = DriverManager.getConnection(url, username, password);//实例化 /* * 二、创建Statement */ stmt = con.createStatement(); String sql = "select * from emp"; rs = stmt.executeQuery(sql); rs.last();//把光标移动到最后一行 rs.beforeFirst(); /* * 三、循环遍历rs,打印其中数据 * * getString()和getObject()是通用的! */ // while(rs.next()) { // System.out.println(rs.getObject(1) + ", " // + rs.getString("ename") + ", " + rs.getDouble("sal")); // } int count = rs.getMetaData().getColumnCount(); while(rs.next()) {//遍历行 for(int i = 1; i <= count; i++) {//遍历列 System.out.print(rs.getString(i)); if(i < count) { System.out.print(", "); } } System.out.println(); } } catch(Exception e) { throw new RuntimeException(e); } finally { // 关闭 if(rs != null) rs.close(); if(stmt != null) stmt.close(); if(con != null) con.close(); } } }
5.PreparedStatement的使用
它是Statement接口的子接口
优点:防SQL攻击,提高代码的可读性、可维护性,提高效率
使用:
给出SQL模板---所谓SQL模板就是有“?”的SQL语句,其中“?”就是参数
使用Connection的prepareStatement(String sql):即创建它时就让它与一条SQL模板绑定;
调用PreparedStatement的setXXX()系列方法为问号设置值
调用executeUpdate()或executeQuery()方法,但要注意,调用没有参数的方法;
代码
/* * 一、得到PreparedStatement * 1. 给出sql模板:所有的参数使用?来替代 * 2. 调用Connection方法,得到PreparedStatement */ String sql = "select * from t_user where username=? and password=?"; PreparedStatement pstmt = con.prepareStatement(sql); /* * 二、为参数赋值 */ pstmt.setString(1, username);//给第1个问号赋值,值为username pstmt.setString(2, password);//给第2个问号赋值,值为password ResultSet rs = pstmt.executeQuery();//调用查询方法,向数据库发送查询语句 pstmt.setString(1, "liSi"); pstmt.setString(2, "123"); pstmt.executeQuery();
JdbcUtils工具类
作用:
连接数据库的四大参数是:驱动类、url、用户名,以及密码。这些参数都与特定数据库关联,
如果将来想更改数据库,那么就要去修改这四大参数,
那么为了不去修改代码,我们写一个JdbcUtils类,让它从配置文件中读取配置参数,然后创建连接对象。
工具代码v1.0
dbconfig.properties
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mydb1?useUnicode=true&characterEncoding=UTF8 username=root password=123
public class JdbcUtils { private static Properties props = null; // 只在JdbcUtils类被加载时执行一次! static { // 给props进行初始化,即加载dbconfig.properties文件到props对象中 try { InputStream in = JdbcUtils.class.getClassLoader() .getResourceAsStream("dbconfig.properties");//<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">配置文件路径在src目录下</span> props = new Properties(); props.load(in); } catch(IOException e) { throw new RuntimeException(e); } // 加载驱动类 try { Class.forName(props.getProperty("driverClassName")); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } // 获取连接! public static Connection getConnection() throws SQLException { // 得到Connection return DriverManager.getConnection(props.getProperty("url"), props.getProperty("username"), props.getProperty("password")); } }
UserDao(面向接口编程及DAO工厂)
DAO(Data Access Object)模式就是写一个类,把访问数据库的代码封装起来。DAO在数据库与业务逻辑(Service)之间。
实体域,即操作的对象,例如我们操作的表是user表,那么就需要先写一个User类;
DAO模式需要先提供一个DAO接口;
然后再提供一个DAO接口的实现类;
再编写一个DAO工厂,Service通过工厂来获取DAO实现。
修改项目:
1.把UserDao修改为接口,然后把原来的UserDao修改类名为UserDaoImpl
2.修改UserService中对UserDao的实例化:private UserDao userDao =DaoFactory.getUserDao()
3.创建DaoFactory,提供getUserDao()
代码
工厂类/** * 通过配置文件得到dao实现类的名称! * 通过类名称,完成创建类对象!(反射完成的!) * @author cxf * */ public class DaoFactory { private static Properties props = null; static { // 加载配置文件内容到props对象中 try { InputStream in = DaoFactory.class .getClassLoader().getResourceAsStream("dao.properties"); props = new Properties(); props.load(in); } catch(Exception e) { throw new RuntimeException(e); } } /** * 返回一个具体UserDao的实现类对象 * @return */ public static UserDao getUserDao() { /** * 给出一个配置文件,文件中给出UserDao接口的实现类名称! * 我们这个方法,获取实现类的类名,通过反射完成创建对象! */ /* * 得到dao实现类的名称 */ String daoClassName = props.getProperty("cn.itcast.usermng.dao.UserDao"); /* * 通过反射来创建实现类的对象 */ try { Class clazz = Class.forName(daoClassName); return (UserDao)clazz.newInstance(); } catch(Exception e) { throw new RuntimeException(e); } } }
时间类型
数据库类型与java中类型的对应关系:
DATE → java.sql.Date
TIME → java.sql.Time
TIMESTAMP → java.sql.Timestamp
领域对象(domain)中的所有属性不能出现java.sql包下的东西!即不能使用java.sql.Date;
ResultSet#getDate()返回的是java.sql.Date()
PreparedStatement#setDate(int, Date),其中第二个参数也是java.sql.Date
时间类型的转换:
java.util.Date java.sql.Date、Time、Timestamp
把util的Date转换成毫秒值
使用毫秒值创建sql的Date、Time、Timestamp
java.sql.Date、Time、Timestamp java.util.Date
这一步不需要处理了:因为java.sql.Date是java.util.Date;
java.util.Datedate = new java.util.Date();
longl = date.getTime();
java.sql.DatesqlDate = new java.sql.Date(l);
1 Java中的时间类型
java.sql包下给出三个与数据库相关的日期时间类型,分别是:
Date:表示日期,只有年月日,没有时分秒。会丢失时间;
Time:表示时间,只有时分秒,没有年月日。会丢失日期;
Timestamp:表示时间戳,有年月日时分秒,以及毫秒。
这三个类都是java.util.Date的子类。
2 时间类型相互转换
把数据库的三种时间类型赋给java.util.Date,基本不用转换,因为这是把子类对象给父类的引用,不需要转换。
java.sql.Date date = …
java.util.Date d = date;
java.sql.Time time = …
java.util.Date d = time;
java.sql.Timestamp timestamp = …
java.util.Date d = timestamp;
当需要把java.util.Date转换成数据库的三种时间类型时,这就不能直接赋值了,这需要使用数据库三种时间类型的构造器。java.sql包下的Date、Time、TimeStamp三个类的构造器都需要一个long类型的参数,表示毫秒值。创建这三个类型的对象,只需要有毫秒值即可。我们知道java.util.Date有getTime()方法可以获取毫秒值,那么这个转换也就不是什么问题了。
java.utl.Date d = new java.util.Date();
java.sql.Date date = newjava.sql.Date(d.getTime());//会丢失时分秒
Time time = new Time(d.getTime());//会丢失年月日
Timestamp timestamp = newTimestamp(d.getTime());
大数据
1 什么是大数据
所谓大数据,就是大的字节数据,或大的字符数据。标准SQL中提供了如下类型来保存大数据
标准SQL大数据类型
类型 |
长度 |
tinyblob |
28--1B(256B) |
blob |
216-1B(64K) |
mediumblob |
224-1B(16M) |
longblob |
232-1B(4G) |
tinyclob |
28--1B(256B) |
clob |
216-1B(64K) |
mediumclob |
224-1B(16M) |
longclob |
232-1B(4G) |
在mysql中没有提供tinyclob、clob、mediumclob、longclob四种类型
而是使用tinytext,text,mediumtext,longtext
代码
把mp3保存到数据库中!
com.mysql.jdbc.PacketTooBigException: Packet for query is too large (9802817 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.
在my.ini中设置,在[mysqld]下添加max_allowed_packet=10M,例如:
[mysqld]
max_allowed_packet=64M
/** * 大数据 * @author cxf * */ public class Demo4 { /** * 把mp3保存到数据库中。 * @throws SQLException * @throws IOException * @throws FileNotFoundException */ @Test public void fun1() throws Exception { /* * 1. 得到Connection * 2. 给出sql模板,创建pstmt * 3. 设置sql模板中的参数 * 4. 调用pstmt的executeUpdate()执行 */ Connection con = JdbcUtils.getConnection(); String sql = "insert into tab_bin values(?,?,?)"; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setInt(1, 1); pstmt.setString(2, "流光飞舞.mp3"); /** * 需要得到Blob * 1. 我们有的是文件,目标是Blob * 2. 先把文件变成byte[] * 3. 再使用byte[]创建Blob */ // 把文件转换成byte[] byte[] bytes = IOUtils.toByteArray(new FileInputStream("F:/流光飞舞.mp3")); // 使用byte[]创建Blob Blob blob = new SerialBlob(bytes); // 设置参数 pstmt.setBlob(3, blob); pstmt.executeUpdate(); } /** * 从数据库读取mp3 * @throws SQLException */ @Test public void fun2() throws Exception { /* * 1. 创建Connection */ Connection con = JdbcUtils.getConnection(); /* * 2. 给出select语句模板,创建pstmt */ String sql = "select * from tab_bin"; PreparedStatement pstmt = con.prepareStatement(sql); /* * 3. pstmt执行查询,得到ResultSet */ ResultSet rs = pstmt.executeQuery(); /* * 4. 获取rs中名为data的列数据 */ if(rs.next()) { Blob blob = rs.getBlob("data"); /* * 把Blob变成硬盘上的文件! */ /* * 1. 通过Blob得到输入流对象 * 2. 自己创建输出流对象 * 3. 把输入流的数据写入到输出流中 */ InputStream in = blob.getBinaryStream(); OutputStream out = new FileOutputStream("c:/lgfw.mp3"); IOUtils.copy(in, out); } } }
批处理
MySQL的批处理也需要通过参数来打开:rewriteBatchedStatements=true
1 Statement批处理
批处理就是一批一批的处理,而不是一个一个的处理!
当你有10条SQL语句要执行时,一次向服务器发送一条SQL语句,这么做效率上很差!
处理的方案是使用批处理,即一次向服务器发送多条SQL语句,然后由服务器一次性处理。
批处理只针对更新(增、删、改)语句,批处理没有查询什么事儿!
可以多次调用Statement类的addBatch(Stringsql)方法,
把需要执行的所有SQL语句添加到一个“批”中,
然后调用Statement类的executeBatch()方法来执行当前“批”中的语句。
voidaddBatch(String sql):添加一条语句到“批”中;
int[]executeBatch():执行“批”中所有语句。返回值表示每条语句所影响的行数据;
voidclearBatch():清空“批”中的所有语句。
for(int i = 0; i < 10; i++) { String number = "S_10" + i; String name = "stu" + i; int age = 20 + i; String gender = i % 2 == 0 ? "male" : "female"; String sql = "insert into stu values('" + number + "', '" + name + "', " + age + ", '" + gender + "')"; stmt[内部有个集合,用来装载sql语句].addBatch(sql); } stmt.executeBatch[执行批,即一次把批中的所有sql语句发送给服务器]();
当执行了“批”之后,“批”中的SQL语句就会被清空!也就是说,连续两次调用executeBatch()相当于调用一次!因为第二次调用时,“批”中已经没有SQL语句了。
还可以在执行“批”之前,调用Statement的clearBatch()方法来清空“批”!
2PreparedStatement批处理
PreparedStatement的批处理有所不同,因为每个PreparedStatement对象都绑定一条SQL模板。
所以向PreparedStatement中添加的不是SQL语句,而是给“?”赋值。
/** * 批处理 * @author cxf * */ public class Demo5 { /** * pstmt对象内部有集合 * 1. 用循环疯狂向pstmt中添加sql参数,它自己有模板,使用一组参数与模板罚没可以匹配出一条sql语句 * 2. 调用它的执行批方法,完成向数据库发送! * @throws SQLException */ @Test public void fun5() throws SQLException { /* * pstmt: * > 添加参数到批中 * > 执行批! */ Connection con = JdbcUtils.getConnection(); String sql = "INSERT INTO t_stu VALUES(?,?,?,?)"; PreparedStatement pstmt = con.prepareStatement(sql); // 疯狂的添加参数 for(int i = 0; i < 10000; i++) { pstmt.setInt(1, i+1); pstmt.setString(2, "stu_" + i); pstmt.setInt(3, i); pstmt.setString(4, i%2==0?"男":"女"); pstmt.addBatch();//添加批!这一组参数就保存到集合中了。 } long start = System.currentTimeMillis(); pstmt.executeBatch();//执行批! long end = System.currentTimeMillis(); System.out.println(end - start);//412764, 301 } }

epc+o模式就是指设计、采购等等为一体的总承包框架,它是在epc里面引申出来的一些运营环节;即在建设期内时,总承包商除了要去承担传统意义上的设计任务以外,还要去包揽在运营期内的所有维护任务。该模式可以极大程度提高许多项目的运营效率,也可以迅速降低运营成本。

设置无线网络很常见,但选择或更改网络类型可能会令人困惑,尤其是在您不知道后果的情况下。如果您正在寻找有关如何在Windows11中将网络类型从公共更改为私有或反之亦然的建议,请继续阅读以获取一些有用的信息。Windows11中有哪些不同的网络配置文件?Windows11附带了许多网络配置文件,这些配置文件本质上是可用于配置各种网络连接的设置集。如果您在家中或办公室有多个连接,这将非常有用,因此您不必每次连接到新网络时都进行所有设置。专用和公用网络配置文件是Windows11中的两种常见类型,但通

Part1聊聊Python序列类型的本质在本博客中,我们来聊聊探讨Python的各种“序列”类,内置的三大常用数据结构——列表类(list)、元组类(tuple)和字符串类(str)的本质。不知道你发现没有,这些类都有一个很明显的共性,都可以用来保存多个数据元素,最主要的功能是:每个类都支持下标(索引)访问该序列的元素,比如使用语法Seq[i]。其实上面每个类都是使用数组这种简单的数据结构表示。但是熟悉Python的读者可能知道这3种数据结构又有一些不同:比如元组和字符串是不能修改的,列表可以

随着短视频平台的盛行,视频矩阵账号营销已成为一种新兴营销方式。通过在不同平台上创建和管理多个账号,企业和个人能够实现品牌推广、粉丝增长和产品销售等目标。本文将为您探讨如何有效运用视频矩阵账号,并介绍不同类型的视频矩阵账号。一、视频矩阵账号怎么做?要想做好视频矩阵账号,需要遵循以下几个步骤:首先要明确你的视频矩阵账号的目标是什么,是为了品牌传播、粉丝增长还是产品销售。明确目标有助于制定相应的策略。2.选择平台:根据你的目标受众,选择合适的短视频平台。目前主流的短视频平台有抖音、快手、火山小视频等。

Go函数可以返回多个不同类型的值,返回值类型在函数签名中指定,并通过return语句返回。例如,函数可以返回一个整数和一个字符串:funcgetDetails()(int,string)。实战中,一个计算圆面积的函数可以返回面积和一个可选错误:funccircleArea(radiusfloat64)(float64,error)。注意事项:如果函数签名未指定类型,则返回空值;建议使用显式类型声明的return语句以提高可读性。

使用动态语言一时爽,代码重构火葬场。相信你一定听过这句话,和单元测试一样,虽然写代码的时候花费你少量的时间,但是从长远来看,这是非常值得的。本文分享如何更好的理解和使用Python的类型提示。1、类型提示仅在语法层面有效类型提示(自PEP3107开始引入)用于向变量、参数、函数参数以及它们的返回值、类属性和方法添加类型。Python的变量类型是动态的,可以在运行时修改,为代码添加类型提示,仅在语法层面支持,对代码的运行没有任何影响,Python解释器在运行代码的时候会忽略类型提示。因此类型提

C++函数有以下类型:简单函数、const函数、静态函数、虚函数;特性包括:inline函数、默认参数、引用返回、重载函数。例如,calculateArea函数使用π计算给定半径圆的面积,并将其作为输出返回。

Java注解用于为代码元素提供元数据,可用于元编程、错误检查、代码生成、文档生成和反射,其中Spring框架广泛使用注解进行配置,简化了应用程序开发。


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

MinGW - Minimalist GNU for Windows
This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

WebStorm Mac version
Useful JavaScript development tools

Atom editor mac version download
The most popular open source editor

ZendStudio 13.5.1 Mac
Powerful PHP integrated development environment
